vue版本:v2.7.10
src/platforms/web/runtime/index.ts
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
src/core/instance/lifecycle.ts
export function mountComponent(
vm: Component,
el: Element | null | undefined,
hydrating?: boolean
): Component {
vm.$el = el
callHook(vm, 'beforeMount')
const updateComponent = () => {
vm._update(vm._render(), hydrating)
}
const watcherOptions: WatcherOptions = {
before() {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate')
}
}
}
new Watcher(
vm,
updateComponent,
noop,
watcherOptions,
true /* isRenderWatcher */
)
if (vm.$vnode == null) {
vm._isMounted = true
callHook(vm, 'mounted')
}
return vm
}
看一下Vue元素挂载函数:$mount -> mountComponent
在mountComponent是创建了渲染Watcher,Watcher的回调更新函数是updateComponent,其实现是:vm._update(vm._render(), hydrating)
。因为Vue组件元素渲染的核心在于vm._update和vm._render
vm._update
src/core/instance/lifecycle.ts
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
const vm: Component = this
const prevEl = vm.$el
const prevVnode = vm._vnode
const restoreActiveInstance = setActiveInstance(vm)
vm._vnode = vnode
if (!prevVnode) {
vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)
} else {
vm.$el = vm.__patch__(prevVnode, vnode)
}
restoreActiveInstance()
}
vm._update
函数传入一个vnode实例,通过vm.__patch__
进行元素更新
src/platforms/web/runtime/index.ts
Vue.prototype.__patch__ = inBrowser ? patch : noop
src/platforms/web/runtime/patch.ts
export const patch: Function = createPatchFunction({ nodeOps, modules })
接下来就是Vue核心的diff算法了,内容比较复杂,在Vue 源码-diff算法
篇章详细描述。
vm._render
src/core/instance/render.ts
Vue.prototype._render = function (): VNode {
const vm: Component = this
const { render, _parentVnode } = vm.$options
...
vm.$vnode = _parentVnode!
let vnode
try {
setCurrentInstance(vm)
currentRenderingInstance = vm
vnode = render.call(vm._renderProxy, vm.$createElement)
} finally {
currentRenderingInstance = null
setCurrentInstance()
}
...
vnode.parent = _parentVnode
return vnode
}
vm._render通过render.call(vm._renderProxy, vm.$createElement)
创建一个vnode实例并返回,用于vm._update
进行vnode的对比和更新。render函数的实现一般是h => h(App)
,因为最终的实现是vm.$createElement(APP)
,这里的APP
是单文档组件导出的组件选项对象。
vm.$createElement 将在Vue源码-VNode
篇章详细介绍。
而单文件组件的导出内容得通过vue-loader文档进行学习。