第13章、异步组件与函数式组件

13.1 异步组件要解决的问题

用户可以简单通过 import 异步导入组件。

  1. <template>
  2. <component :is="asyncComp">
  3. </template>
  4. <script>
  5. export default {
  6. setup() {
  7. const asyncComp = shallowRef(null)
  8. import ('CompB.vue').then(CompB => asyncComp.value = CompB)
  9. }
  10. }
  11. </script>

但我们还需要考虑组件加载失败,Loading 显示,失败重试等问题。

13.2 异步组件的实现原理

卸载函数增加卸载组件的逻辑

  1. function unmount(vnode) {
  2. if (vnode.type === Fragment) {
  3. vnode.children.forEach((c) => unmount(c))
  4. return
  5. } else if (typeof vnode.type === 'object') {
  6. unmount(vnode.component.subTree)
  7. return
  8. }
  9. const parent = vnode.el.parentNode
  10. if (parent) {
  11. parent.removeChild(vnode.el)
  12. }
  13. }

在异步组件增加完善的逻辑,具体含义见代码注释。

  1. function defineAsyncComponent(options) {
  2. if (typeof options === 'function') {
  3. options = {
  4. loader: options,
  5. }
  6. }
  7. const { loader } = options
  8. let InnerComp = null
  9. let retries = 0
  10. function load() {
  11. return loader().catch((err) => {
  12. if (options.onError) {
  13. // 函数返回Promise 并让用户在retry中调用resolve
  14. // 这样用户retry之后 通过load().then() 可以获取组件值
  15. // 即使又失败 就是又返回一个Promise 对象 还是要获取Promise中resolve的值
  16. // 所以这样可以多次调用retry
  17. return new Promise((resolve, reject) => {
  18. const retry = () => {
  19. resolve(load())
  20. retries++
  21. }
  22. const fail = () => reject(err)
  23. options.onError(retry, fail, retries)
  24. })
  25. } else {
  26. throw err
  27. }
  28. })
  29. }
  30. return {
  31. name: 'AsyncComponentWrapper',
  32. setup() {
  33. const loaded = ref(false)
  34. const error = shallowRef(null)
  35. const loading = ref(false)
  36. const loadingTimer = null
  37. if (options.delay) {
  38. // 设置options.delay的话,在options.delay时间之后再把loading设置为true,
  39. // 防止组件加载比较快的情况下出现loading一闪而过导致用户体验差
  40. loadingTimer = setTimeout(() => {
  41. loading.value = true
  42. }, options.delay)
  43. } else {
  44. loading.value = true
  45. }
  46. load() // 使用load函数加载组件
  47. .then((c) => {
  48. InnerComp = c
  49. loaded.value = true
  50. })
  51. // 记录错误
  52. .catch((err) => (error.value = err))
  53. // 加载后设置加载成功 loading为false
  54. .finally(() => {
  55. loading.value = false
  56. clearTimeout(loadingTimer)
  57. })
  58. let timer = null
  59. if (options.timeout) {
  60. timer = setTimeout(() => {
  61. const err = new Error('异步组件加载超时')
  62. error.value = err
  63. }, options.timeout)
  64. }
  65. // 保证组件被卸载时清除定时器
  66. onUmounted(() => clearTimeout(timer))
  67. // 占位内容
  68. const placeholder = { type: Text, children: '占位' }
  69. return () => {
  70. // 加载成功渲染组件 否则渲染占位符
  71. if (loaded.value) {
  72. return { type: InnerComp }
  73. } else if (error.value && options.errorComponent) {
  74. // 存在错误返回error对应组件
  75. return { type: options.errorComponent, props: { error: error.value } }
  76. } else if (loading.value && options.loadingComponent) {
  77. // 加载中返回loading对应组件
  78. return { type: options.loadingComponent }
  79. }
  80. return placeholder
  81. }
  82. },
  83. }
  84. }

13.3 函数式组件

函数式组件本质就是一个普通函数,该函数的返回值是虚拟 DOM。在 Vue3 中函数式组件的性能和普通组件差不多,但是比较简单。

实现也很简单,就是在 patch 新增对函数的支持,同时在组件挂载时,把 type 作为渲染函数。

  1. function patch(n1, n2, container, anchor) {
  2. //...
  3. // 新增了对函数的判断
  4. if (typeof type === 'object' || typeof type === 'function') {
  5. // 组件
  6. if (!n1) {
  7. // 挂载
  8. mountComponent(n2, container, anchor)
  9. } else {
  10. patchComponent(n1, n2, anchor)
  11. }
  12. }
  13. }
  14. function mountComponent(vnode, container, anchor) {
  15. const isFunctional = typeof vnode.type === 'function'
  16. let componentOptions = vnode.type
  17. if (isFunctional) {
  18. componentOptions = {
  19. render: vnode.type,
  20. props: vnode.type.props,
  21. }
  22. }
  23. // ...
  24. }

使用方法:

  1. function MyFuncComp(props) {
  2. return {
  3. type: 'h1',
  4. children: props.title
  5. }
  6. }
  7. MyFuncComp.props = {
  8. title: String
  9. }
  10. const vnode = {
  11. type: MyFuncComp,
  12. props: {
  13. title: '函数式组件'
  14. }
  15. }

《Vue.js 设计与实现》读书笔记 - 第13章、异步组件与函数式组件的更多相关文章

  1. 【vue.js权威指南】读书笔记(第一章)

    最近在读新书<vue.js权威指南>,一边读,一边把笔记整理下来,方便自己以后温故知新,也希望能把自己的读书心得分享给大家. [第1章:遇见vue.js] vue.js是什么? vue.j ...

  2. 【vue.js权威指南】读书笔记(第二章)

    [第2章:数据绑定] 何为数据绑定?答曰:数据绑定就是将数据和视图相关联,当数据发生变化的时候,可以自动的来更新视图. 数据绑定的语法主要分为以下几个部分: 文本插值:文本插值可以说是最基本的形式了. ...

  3. C++ primer plus读书笔记——第13章 类继承

    第13章 类继承 1. 如果购买厂商的C库,除非厂商提供库函数的源代码,否则您将无法根据自己的需求,对函数进行扩展或修改.但如果是类库,只要其提供了类方法的头文件和编译后的代码,仍可以使用库中的类派生 ...

  4. js高程读书笔记(1-3章)

    一.js简介 js是一种专为与网页交互而设计的脚本语言,由以下三个不同的部分组成: 1.ECMAScript,由ECMA-262(它规定了语言的这些组成部分:语法,类型,语句,关键字,保留字,操作符, ...

  5. 《Android内核剖析》读书笔记 第13章 View工作原理【View重绘过程】

    计算视图大小的过程(Measure) 视图大小,准确的来说应该是指视图的布局大小:我们在layout.xml中为每个UI控件设置的layout_width/layout_height两个属性被用来设置 ...

  6. Javascript设计模式与开发实践读书笔记(1-3章)

    第一章 面向对象的Javascript 1.1 多态在面向对象设计中的应用   多态最根本好处在于,你不必询问对象“你是什么类型”而后根据得到的答案调用对象的某个行为--你只管调用行为就好,剩下的一切 ...

  7. INSPIRED启示录 读书笔记 - 第13章 产品原则

    确定什么最重要 产品原则是对团队信仰和价值观的总结,用来指导产品团队作出正确的决策和取舍.它体现了产品团队的目标和愿景,是产品战略的重要组成部分.从形式上看,它是一系列明确的.体现团队特色的产品价值准 ...

  8. JavaScript高级程序设计第三版-读书笔记(1-3章)

    这是我第一次用markdown,也是我第一次在网上记录我自己的学习过程. 第一章 JavaScript主要由以下三个不同的部分构成 ECMAScript   提供核心语言功能 DOM     提供访问 ...

  9. 《Javascript高级程序设计》读书笔记(1-3章)

    第一章 JavaScript简介 1.1 JavaScript简史 略 1.2 JavaScript实现 虽然 JavaScript 和 ECMAScript 通常都被人们用来表达相同的含义,但 Ja ...

  10. 《C和指针》 读书笔记 -- 第13章 高级指针话题

    1.函数指针 int (*f)(); int *(*f[])(); 用途: [1]回调函数 e.g. /*在一个单链表中查找指定值*/ Node *search_list(Node *node,voi ...

随机推荐

  1. 错误记录java: JDK isn't specified for module

    跑苍穹外卖的时候遇到了 java: JDK isn't specified for module 'sky-pojo'这一问题 解决办法是通过修改JDK版本,这个项目用的springboot比较早,可 ...

  2. awk替换指定行指定列内容

    例如表格中数值如下1,2,3,41,2,1,22,3,2,3怎么样在原表中,把第二行第三个1替换为5. awk -F"," 'NR==2{$3=5} 1' file.txt -F ...

  3. 【Java】讲讲StreamAPI

    预设场景: 从Mybatis调用Mapper得到的用户集合 List<UserDTO> userList = new ArrayList<>(); 常用的几种API用法示例: ...

  4. 【Java】再谈Springboot 策略模式

    第一次使用策略模式是一年前的一个项目: https://www.cnblogs.com/mindzone/p/16046538.html 当时还不知道Spring支持集合类型的自动装配 在最近一个项目 ...

  5. 【DataBase】SQL优化问题

    在DAO层的动态SQL: //订单新增,查询配件主数据 @SuppressWarnings("rawtypes") public PageInfoDto getPartsForPa ...

  6. 【C】Re11 剩下的笔记

    关于字符常量问题: #include <stdio.h> #include <stdlib.h> #include <string.h> void string01 ...

  7. 【DataBase】MySQL 28 流程控制

    一.分支结构 1.IF函数 语法: IF(表达式1, 表达式2, 表达式3) 类似三元运算符,表达式1返回True Or False True执行表达式2,False执行表达式3 IF实现多分枝结构 ...

  8. 【FastDFS】环境搭建 02 测试

    自带工具测试: 编辑客户端配置文件: vim client.conf 配置完成后,随便上传一个图片到root目录下 运行FastFDS文件上传程序,并将客户端配置文件作为加载参数1,要上传的图片文件位 ...

  9. 制约国产深度学习框架发展的根本原因 —— AI芯片的无法自主生产或量产

    秉着没事就胡言乱语的宗旨,这里在接着胡说八道一下. 国外的深度学习框架如TensorFlow.pytorch.Jax打的如火如荼,按照以往惯例我们是不应该去做自主研发软件系统的,毕竟硬件不在掌握之下, ...

  10. 七牛云-存储区域代码:报错:"statusCode": 400,"error": incorrect region, please use up-cn-east-2.qiniup.com ——【图床】Typora 七牛云图床 配置文件

    使用PicList对七牛云配置图床,报错信息: 2023-12-13 19:52:19 [PicList ERROR] { "method": "POST", ...