归一化操作其实就是将多维的数组,合并转换成一个一维的数组。在 Vue 中归一化分为三个级别,
- 0:不需要进行归一化
- 1:只需要简单的归一化处理,将数组打平一层
- 2:完全归一化,将一个 N 层的 children 完全打平为一维数组
归一化的代码位于src/core/vdom/create-element.js
的createElement
中,我们的vm._c
和vm.$createElement
都会调用这个函数。
1 | const SIMPLE_NORMALIZE = 1 |
vm._c
传入的alwaysNormalize
为false
,而vm.$createElement
传入的alwaysNormalize
为true
。所以最终前者会调用simpleNormalizeChildren
来处理children
,后者会使用normalizeChildren
。
The template compiler attempts to minimize the need for normalization by
statically analyzing the template at compile time.
For plain HTML markup, normalization can be completely skipped because the
generated render function is guaranteed to return Array. There are
two cases where extra normalization is needed.
1. simpleNormalizeChildren
When the children contains components - because a functional component
may return an Array instead of a single root. In this case, just a simple
normalization is needed - if any child is an Array, we flatten the whole
thing with Array.prototype.concat. It is guaranteed to be only 1-level deep
because functional components already normalize their own children.
1 | export function simpleNormalizeChildren(children: any) { |
如果有任何一个 child 是数组,那么直接整个 children 打平一层,例如:
1 | var arr = [1,2,3,4,[5,6,[7,8]]] |
我们可以试着手动调用一下vm._c
:
1 | var h = vm._c; |
返回的 vnode 结果关键属性有:
1 | { |
可以看到只打平了一层。
2. normalizeChildren
When the children contains constructs that always generated nested Arrays,
e.g. ,, v-for, or when the children is provided by user
with hand-written render functions / JSX. In such cases a full normalization
is needed to cater to all possible types of children values.
1 | export function normalizeChildren(children: any): ?Array<VNode> { |
其实就是利用递归来处理的,同时处理了一些边界情况。同样手动调用下vm.$createElement
来触发此逻辑:
1 | var h = vm.$createElement; |
返回 vnode 结果的关键属性:
1 | { |
可以看到全部都打平了。