createElement
createElement
有6个属性,context
是传入的vm
实例,tag
标签,data
是跟vnode
相关的数据,children
是vnode
的字节点,可以构建出整个vnode
的tree
,下面第一个判断是对参数个数的处理,如果没有传入data,就往前移,data是undefined。下面的是通过对awaysNormalize
的判断,对normalizationType
赋值常量,最终createElement
对参数进行封装处理后返回_createElement
调用
_createElemenet
首先对data
进行了一层校验,如果data
是响应式的就会报警告Avoid using observed data object as vnode data...
,然后返回createEmptyVNode()
实际上就是一个注释节点。
然后判断了data.is
并负值给了tag
,如果tag
不是一个真值的话,也返回一个注释节点。
这个是_createElement做的比较重要的一个操作对所有的children 进行了normalize操作
simpleNormalizeChildren
中对每个元素进行遍历,如果元素也是数组的话,就把嵌套数组修改成一维数组
normalizeChildren对children进行类型判断,如果children是基础类型就直接返回一维数组,这个数组长度只有一个,createTextVNode()
前三个值是tag, data, children
都是undefined
,是一个文本的vnode
否则判断是不是array类型,如果是array类型就调用mormalizeArrayChildren
,否则返回undefined
这个函数首先定义了返回的数组,然后对children
进行遍历判断,如果发现字节点是一个array
,就会递归调用normalizeArrayChildren
,放到这个节点上面
if (isTextNode(c[0]) && isTextNode(last)) {
res[lastIndex] = createTextVNode(last.text + (c[0]: any).text)
c.shift()
}
这里是一个优化如果我最后处理的节点和下次第一个处理的节点如果都是文本节点,就合并到一个
如果判断children是一个基础类型,如果判断是一个文本类型的话就合并文本节点,否则push一个textNode
再否则就是一个正常的vnode,会对v-for之类的做一些处理,然后push到res上
回到_createElement
,判断tag
是不是string
类型,再判断tag
是不是html
保留的原生标签,如果是就创建平台保留标签,传入参数实例化一个VNode
生成vnode
,这个vnode
就是render
函数返回的vnode
,执行了render.call()
,实际上是createElement
的返回值,再把这个vnode,传给vm._render调用的方法