You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
functionnormalizeArrayChildren(children: any,nestedIndex?: string): Array<VNode>{
const res=[]// 存放结果leti, c, lastIndex, last
for(i=0;i<children.length;i++){
c =children[i]if(isUndef(c)||typeofc==='boolean')continuelastIndex=res.length-1last=res[lastIndex]// nestedif(Array.isArray(c)){if(c.length>0){// 递归遍历数组 c ,将数组内的元素都转为文本节点c=normalizeArrayChildren(c,`${nestedIndex||''}_${i}`)if(isTextNode(c[0])&&isTextNode(last)){// 合并文本节点,是将 res 的最后一个节点和 c 的第一个节点的文本内容进行合并res[lastIndex]=createTextVNode(last.text+(c[0]: any).text)c.shift()}// 利用 apply 将数组 c 的元素逐一 push 到 res 中,从而将多维数组转为一维数组// 相当于 res.push(...c)res.push.apply(res,c)}}elseif(isPrimitive(c)){if(isTextNode(last)){// 如果 res 的最后一个元素是文本节点,将其文本与 c 进行合并res[lastIndex]=createTextVNode(last.text+c)}elseif(c!== ''){// convert primitive to vnoderes.push(createTextVNode(c))}}else{if(isTextNode(c)&&isTextNode(last)){// 如果 c 是文本节点,将 c 的文本与 res 的最后一个元素的文本进行合并res[lastIndex]=createTextVNode(last.text+c.text)}else{// default key for nested array children (likely generated by v-for)if(isTrue(children._isVList)&&isDef(c.tag)&&isUndef(c.key)&&isDef(nestedIndex)){c.key=`__vlist${nestedIndex}_${i}__`}// 否则 c 已经是 VNode 类型了res.push(c)}}}returnres}
可以看到,normalizeArrayChildren的主要的作用是将 children 数组打平为一个一维数组,并且将 children 内的元素全部转为虚拟节点 VNode,res 最终返回的结果是 [VNode, VNode, ...]。
我们尝试调用下$createElement方法。
前言
vue 源码系列的分享我会尽可能的表述清楚一些,简单一些。
createElement
上一节中我们知道 vue 生成虚拟 DOM 时候,使用的是
createElement
方法。下面我们就看下createElement
方法的庐山真面目。所以实际上,
createElement
方法是对_createElement
方法的封装。真正创建虚拟DOM
的是_createElement
函数。继续看下_createElement
方法。_createElement
它先对
children
做个处理,是将children
数组打平一个层级。children 的处理
先看下简单点的
simpleNormalizeChildren
方法。实际上是使用
Array.prototype.concat.apply([], children)
将children
数组直接打平一层。尝试手动调用下_c
方法。结果如下,可以看到,只打平了一层数组。

而
normalizeChildren
方法则是,将children
数组打平为一个一维数组。我们来看下它是如何实现的。接下来,我们看下
normalizeArrayChildren
方法做了什么操作。可以看到,
normalizeArrayChildren
的主要的作用是将children
数组打平为一个一维数组,并且将children
内的元素全部转为虚拟节点VNode
,res 最终返回的结果是[VNode, VNode, ...]
。我们尝试调用下
$createElement
方法。结果如下图,可以看到,

children
数组被打平为一个一维数组了,并且children
数组内的元素全部被转为虚拟DOM
了。生成虚拟 DOM
继续看
_createElement
第二部分代码。这部分比较简单,代码如下:new VNode
直接生成虚拟DOM
。createComponent
生成虚拟DOM
。然鹅
createComponent
又是什么呢。这个有点绕,我们一点一点看吧。
首先,
context.$options._base
是什么呢。这个是在 Vue 初始化时候,调用了initGlobalAPI
函数。其中有两行代码是:所以,
baseCtor
就是Vue
本身。而initExtend
是什么呢。所以,
vue.extend()
会返回一个VueComponent
函数,它拥有vue
的完整功能。installComponentHooks
安装一些钩子,如init、prepatch、insert、destory
,在将 vnode 转为 真实 DOM 时会用到。createComponent
最后一部分,就是创建组件类型的虚拟 DOM。总结
createElement
对_createElement
做了个封装。_createElement
包含了两部分,一是children
的处理,一是创建虚拟DOM
children
的处理,根据render
的不同,处理方式也有所区别。render
是由template
编译产生时,使用的是simpleNormalizeChildren
将children
数组降低一层。render
是用户手写传入时,使用的是normalizeChildren
将children
数组转为一个一维数组,其内部的元素全部由vnode
组成。DOM
时。new Vnode()
创建虚拟DOM
。createComponent
,它的作用,一是将组件对象转为Vue
的子类,使其具有Vue
的完整功能。二是初始化一些将虚拟DOM
转为真实DOM
的钩子。三是使用new Vnode()
创建组件类型的虚拟DOM
,并将组件相关的信息保存在componentOptions
中。The text was updated successfully, but these errors were encountered: