乐趣区

关于vue.js:基于-Vue3-打造前台中台通用提效解决方案完结

Download: https://www.itwangzi.cn/2624….

以前始终认为,VNode 也能像 DOM 那样,依据 children 属性,将 VNode 连贯组成一棵树。但最近我发现这是不对的,VNode 不能独自组成一棵残缺的页面树。Demo 咱们用一个例子来阐明一下,Vue Playground 在线预览链接 [1]App.vue<script setup>import Comp from ‘./Comp.vue'</script><template>  <h1>Hello World!</h1>  <Comp> test-slot </Comp></template>Comp.vue<template>  <h2>    slot:<slot></slot>  </h2></template> 对应的比拟残缺的树结构如下(图差不多看看就行,文章前面会有解析):

红框中的内容,是理论渲染到页面的内容。

那为什么不是独自将 VNode 连贯组合成树,就像下图一样:

要搞清楚这个问题,咱们先来看看 VNode 是怎么创立的。VNode 的创立下图是一个 vue 单文件组件的编译后果:

咱们晓得,Vue 的 template 模板最终都会编译成渲染函数,如右图,略微一看,如同一个函数都不意识,但其实将 createELementVNode 换成咱们熟知的 h 函数,就很好了解了。1. _createElementBlock(_Fragment, …),创立一个 Fragment,(如果 Vue 组件内有多个根元素,会用 Fragment 包裹,以保障一个组件的根元素只有一个)2. _hoisted_1,动态的 html 内容,会被晋升到渲染函数外,这样每次调用渲染函数,就不须要从新创立 VNode(Vue 的编译优化)3. _createVNode(Comp, …),为 Comp 组件创立 VNode。每次渲染 / 更新视图,都会调用一遍渲染函数,会生成新的 VNode。该组件的渲染函数,会生成如下的 VNode:

从这个例子能够看出:1. 渲染函数会创立一棵 VNode 树,这阐明了 VNode 能够连贯组合成一棵树,但只是组件外部的一棵树 2. VNode 树形容的是以后组件的状态:Comp 组件的 VNode 的 children 是 test slots 文本。这与 DOM 树是有区别的 3. children 属性可能会用于形容非凡的嵌套关系,如:slot 渲染函数是在编译时,从 Vue template 编译进去的,其 VNode 树的嵌套构造,曾经在编译时就确定下来,跟运行时无关。运行时,无非是确定一些 VNode 的值,例如某个变量的绑定、某个 slots 的值 Vue 组件外部实例当两个组件的渲染函数都被执行实现之后,会有两个 VNode Tree:

那么这两个 VNode Tree,是怎么关联起来的,怎么能力组合成一棵残缺的树?ComponentInternalInstance 组件实例起到了关联 VNode Tree 的作用,咱们能够通过应用 getCurrentInstance[2] 获取到组件的外部实例(getCurrentInstance 只裸露给高阶应用场景,典型的比方在库中)它们的关系如下:

• 组件 VNode,可能通过 component 属性,拜访到 ComponentInternalInstance 实例• ComponentInternalInstance 实例,可能通过 subtree 属性,拜访到组件的最顶层内容的 VNode 因而,咱们会失去一开始的残缺的树:

总结本文用一个简略的例子,阐明了 VNode 的创立过程,是每次组件渲染 / 更新时,调用渲染函数创立的 VNode,VNode 树只形容以后组件的状态,其嵌套关系在编译时就曾经确认。VNode 无奈组成一个残缺的树,是因为 VNode 树之前不能间接进行连贯,children 属性不能间接用于连贯 VNode 树,因为存在一些非凡的嵌套关系(如:slot、suspense)一个组件会失去一棵 VNode 树,而 VNode 树,须要用组件外部实例进行连贯。通过组件 VNode 获取组件外部实例,而后再通过 subtree 连贯该组件的 VNode 树。如果没有引入组件的概念,那 VNode 树就是一棵残缺的树。

退出移动版