vue
Version:
Reactive, component-oriented view layer for modern web interfaces.
70 lines (64 loc) • 2.57 kB
JavaScript
/* @flow */
import { isPrimitive } from 'core/util/index'
import VNode, { createTextVNode } from 'core/vdom/vnode'
// 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<VNode>. There are
// two cases where extra normalization is needed:
// 1. When the children contains components - because a functional component
// may return an Array instead of a single root. In this case, just a simple
// nomralization 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.
export function simpleNormalizeChildren (children: any) {
for (let i = 0; i < children.length; i++) {
if (Array.isArray(children[i])) {
return Array.prototype.concat.apply([], children)
}
}
return children
}
// 2. When the children contains constrcuts that always generated nested Arrays,
// e.g. <template>, <slot>, 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.
export function normalizeChildren (children: any): ?Array<VNode> {
return isPrimitive(children)
? [createTextVNode(children)]
: Array.isArray(children)
? normalizeArrayChildren(children)
: undefined
}
function normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNode> {
const res = []
let i, c, last
for (i = 0; i < children.length; i++) {
c = children[i]
if (c == null || typeof c === 'boolean') continue
last = res[res.length - 1]
// nested
if (Array.isArray(c)) {
res.push.apply(res, normalizeArrayChildren(c, `${nestedIndex || ''}_${i}`))
} else if (isPrimitive(c)) {
if (last && last.text) {
last.text += String(c)
} else if (c !== '') {
// convert primitive to vnode
res.push(createTextVNode(c))
}
} else {
if (c.text && last && last.text) {
res[res.length - 1] = createTextVNode(last.text + c.text)
} else {
// default key for nested array children (likely generated by v-for)
if (c.tag && c.key == null && nestedIndex != null) {
c.key = `__vlist${nestedIndex}_${i}__`
}
res.push(c)
}
}
}
return res
}