咱们书接上回,先来看看画重点的地方。
initRender(src/core/instance/render.js)
在前面是怎么个流程,可以出门左转看死磕源码一。
注意看源码先不要被细节缠住
export function initRender (vm: Component) {
// 这有个问题 vm是谁? 前面initMixin时 vm = this
// vm 就是实例对象喽
vm._vnode = null // 初始化 虚拟dom树(当前子组件)
vm._staticTrees = null // 缓存
const options = vm.$options // 配置项
// 父虚拟节点
const parentVnode = vm.$vnode = options._parentVnode
// 渲染时上下文
const renderContext = parentVnode && parentVnode.context
// 插槽相关
vm.$slots = resolveSlots(options._renderChildren, renderContext)
vm.$scopedSlots = emptyObject
// 当然上面这些细节 嘻嘻 重点来了
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
const parentData = parentVnode && parentVnode.data
// 前面说过了 这种判断开发模式的代码可以先或略
if (process.env.NODE_ENV !== 'production') {
defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () => {
!isUpdatingChildComponent && warn(`$attrs is readonly.`, vm)
}, true)
defineReactive(vm, '$listeners', options._parentListeners || emptyObject, () => {
!isUpdatingChildComponent && warn(`$listeners is readonly.`, vm)
}, true)
} else {
defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)
defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true)
}
}
createElement(src/core/vdom/create-element)
上面一段代码中的重点就是createElement顾名思义制造节点。
先把一些 ts的写法干掉, 把生产模式报警告的代码干掉
最后得到这段代码(拿源码对照着撸)
export function _createElement (context, tag, data, children, normalizationType) {
// 首先看看 data 和 data.__ob__ 都存在的话 返回一个空的 vnode
if (isDef(data) && isDef(data.__ob__)) {
return createEmptyVNode()
}
// data和data.is都存在的话 就把data.is赋值给tag
if (isDef(data) && isDef(data.is)) {
tag = data.is
}
// tag不存在返回空的vnode
if (!tag) {
return createEmptyVNode()
}
// 若children[0]是function,则认为是scope slot而不是children
if (Array.isArray(children) && typeof children[0] === 'function') {
data = data || {}
data.scopedSlots = { default: children[0] }
children.length = 0
}
// 这里往下挖就又挖的特别深 记住是对子节点的处理就OK了
// 是标签节点 或者 是文本节点之类的
if (normalizationType === ALWAYS_NORMALIZE) {
children = normalizeChildren(children)
} else if (normalizationType === SIMPLE_NORMALIZE) {
children = simpleNormalizeChildren(children)
}
// 根据不同的情况创建不同类型的VNode实例并返回
let vnode, ns
if (typeof tag === 'string') {
let Ctor
ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(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))) {
vnode = createComponent(Ctor, data, context, children, tag)
} else {
vnode = new VNode(
tag, data, children,
undefined, undefined, context
)
}
} else {
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)
return vnode
} else {
return createEmptyVNode()
}
}
上面一样最显眼的就是 new VNode``````normalizeChildren simpleNormalizeChildren
这几个个家伙空了接着撸。