# Render-help
# 解析 _c, _m, _l
export function renderMixin () {
// ...
installRenderHelpers(Vue.prototype)
// ...
}
export function installRenderHelpers(target: any) {
// 为 VNode 打上静态标记
target._o = markOnce
// 将值转换为数字
target._n = toNumber
// 将值转换为字符串形式
target._s = toString
// v-for
target._l = renderList
// slot
target._t = renderSlot
// 判读两个值是否相等
target._q = looseEqual
// indexOf
target._i = looseIndexOf
// 静态节点
target._m = renderStatic
target._f = resolveFilter
target._k = checkKeyCodes
target._b = bindObjectProps
// 文本节点
target._v = createTextVNode
// 创建空节点
target._e = createEmptyVNode
target._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
}
# renderList
/*
* genFor 处理的 el.for 为解析出来的可迭代对象
* _l(el.for, (alias, iteratior1, iteratior12) => genElement(tag, data, children))
*/
export function renderList (
val: any,
render: (
val: any,
keyOrIndex: string | number,
index?: number
) => VNode
): ?Array<VNode> {
let ret: ?Array<VNode>, i, l, keys, key
if (Array.isArray(val) || typeof val === 'string') {
ret = new Array(val.length)
for (let i = 0, l = val.length; i < l; i++) {
ret[i] = render(val[i], i)
}
} else if (typeof val === 'number') {
ret = new Array(val)
for (i = 0; i < val; i++) {
ret[i] = render(i + 1, i)
}
} else if (isObject(val)) {
// v-for 的是一个对象
if (hasSymbol && val[Symbol.iterator]) {
ret = []
const iterator: Iterator<any> = val[Symbol.iterator]()
let result = iterator.next()
while (!result.done) {
ret.push(render(result.value, ret.length))
result = iterator.next()
}
} else {
keys = Object.keys(val)
ret = new Array(keys.length)
for (i = 0, l = keys.length; i++) {
key = keys[i]
ret[i] = render(val[key], key, i)
}
}
}
if (!isDef(ret)) {
ret = []
}
// 返回 VNode 数组
(ret: any)._isVList = true
// ret => [genElement(x, y, z), ....]
return ret
}
# renderStatic
export function renderStatic (
index: number,
isInFor: boolean
): VNode | Array<VNode> {
// 缓存
const cached = this._staticTrees || (this._staticTree = [])
let tree = cached[index]
// 已经渲染过 同时不在 v-for 的节点中
if (tree && !isInFor) return tree
// 执行 staticRenderFns 数组中指定元素生成 VNode 并缓存
tree = cached[index] = this.$options.staticRenderFns[index].call(
this._renderProxy,
null,
this
)
// 向 el 添加 isStatic=true, key=`__static__${index}`, isOnce=false
markStatic(tree, `__static__${index}`, false)
return tree
}
# createElement
export function createElement (
context: Component,
tag: any,
data: any,
children: any,
normalizationType: any,
alwaysNormailze: boolean
): VNode | Array<VNode> {
if (Array.isArray(data) || isPrimitive(data)) {
normalizationType = children
children = data
data = undefined
}
if (isTrue(alwaysNormailze)) {
normalizationType = ALWAYS_NORMALIZE
}
return _createElement(context, tag, data, children, normalizationType)
}
export function _createElement(
context: Component,
tag?: string | Class<Component> | Function | Object,
data?: VNodeData,
children?: any,
normalizationType?: number
): VNode | Array<VNode> {
if (isDef(data) && idDef(data.__ob__)) {
// data 不能是一个响应式对象
return createEmptyVNode()
}
// component 的 is 属性
if (isDef(data) && isDef(data.is)) {
tag = data.is
}
if (!tag) {
return createEmptyVNode()
}
// 省略代码 检测唯一键 key 只能是字符串或者数字
if (Array.isArray(children) && typeof children[0] ==== 'function') {
data = data || {}
data.scopedSlots = { default: children[0] }
children.length = 0
}
// 将子元素进行标准化处理
if (normalizationType === ALWAYS_NORMALIZE) {
children = normalizeChildren(children)
} else if (normalizationType === SIMPLE_NORMALIZE) {
children = simpleNormalizeChildren(children)
}
// 重点
let vnode, ns
if (typeof tag === 'string') {
// 平台保留标签、 自定义组件、 不知名标签
let Ctor
ns = (context.$vnode && context.$vnode.ns) || config.getTageNamespace(tag)
// 如果是平台原生标签
if (config.isReservedTag(tag)) {
// 报错
vnode = new VNode(
config.parsePlatformTagName(tag),
data,
children,
undefined,
undefined,
context
)
} else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
// tag 是一个自定义组件
vnode = createComponent(Ctor, data, context, children, tag)
} else {
// 不知名标签
vnode = new VNode(
tag,
data,
children,
undefined,
undefined,
context
)
}
} else {
// tag 不是一个字符串
vnode = createComponent(tag, data, context, children)
}
if (Array.isArray(vnode)) {
return vnode
} else if (isDef(vnode)) {
if (isDef(ns)) applyNs(vnode, ns)
if (isDef(data)) registerDeepBindings(data)
} else {
return createEmptyVnode()
}
}