以前のテンプレート コンパイルの研究ノートでは、テンプレート$mount
がコンパイルされてrender
関数が生成され、呼び出されることがわかっていますmount.call(this, el, hydrating)
。
// src/platforms/web/entry-runtime-with-compiler.js
const mount = Vue.prototype.$mount
// 重新定义 $mount
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && query(el)
// ... 其他代码
// 调用原先 Vue 原型上 $mount 方法
return mount.call(this, el, hydrating)
}
上記mount
は$mount
Vue プロトタイプのメソッドです。
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
mountComponent
これは、コンポーネント インスタンス マウントのエントリ関数であり、ライフ サイクルに関連しているため、このメソッドの特定のコードはソース コードlifecycle
ファイル
// src/core/instance/lifecycle.js
export function mountComponent (
vm: Component,
el: ?Element,
hydrating?: boolean
): Component {
// 将真实的 el 赋值给实例,为后面虚拟 dom 做铺垫
vm.$el = el
// render 函数的判断
if (!vm.$options.render) {
vm.$options.render = createEmptyVNode
if (process.env.NODE_ENV !== 'production') {
if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||
vm.$options.el || el) {
warn(
'You are using the runtime-only build of Vue where the template ' +
'compiler is not available. Either pre-compile the templates into ' +
'render functions, or use the compiler-included build.',
vm
)
} else {
warn(
'Failed to mount component: template or render function not defined.',
vm
)
}
}
}
callHook(vm, 'beforeMount')
let updateComponent
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
updateComponent = () => {
const name = vm._name
const id = vm._uid
const startTag = `vue-perf-start:${
id}`
const endTag = `vue-perf-end:${
id}`
mark(startTag)
const vnode = vm._render()
mark(endTag)
measure(`vue ${
name} render`, startTag, endTag)
mark(startTag)
vm._update(vnode, hydrating)
mark(endTag)
measure(`vue ${
name} patch`, startTag, endTag)
}
} else {
updateComponent = () => {
// 实例挂载
vm._update(vm._render(), hydrating)
}
}
// 创建一个渲染 watcher 实例,主要执行 updateComponent 的方法
new Watcher(vm, updateComponent, noop, {
before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate')
}
}
}, true /* isRenderWatcher */)
hydrating = false
// mounted 钩子函数只执行一次
if (vm.$vnode == null) {
vm._isMounted = true
callHook(vm, 'mounted')
}
return vm
}
mountComponent
上記のコードから、メソッドは主にインスタンスにel
割り当て、vm._update(vm._render(), hydrating)
次に_update
をわかります_render
。
// src/core/instance/render.js
export function initRender (vm: Component) {
// ... 其他代码
// 主要参数: tag, data, children
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
}
export function renderMixin (Vue: Class<Component>) {
installRenderHelpers(Vue.prototype)
Vue.prototype.$nextTick = function (fn: Function) {
return nextTick(fn, this)
}
Vue.prototype._render = function (): VNode {
const vm: Component = this
// 获取 render 函数
const {
render, _parentVnode } = vm.$options
if (_parentVnode) {
vm.$scopedSlots = normalizeScopedSlots(
_parentVnode.data.scopedSlots,
vm.$slots,
vm.$scopedSlots
)
}
vm.$vnode = _parentVnode
let vnode
try {
currentRenderingInstance = vm
// 执行 render 函数生成 vnode
vnode = render.call(vm._renderProxy, vm.$createElement)
} catch (e) {
handleError(e, vm, `render`)
if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {
try {
vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
} catch (e) {
handleError(e, vm, `renderError`)
vnode = vm._vnode
}
} else {
vnode = vm._vnode
}
} finally {
currentRenderingInstance = null
}
// ... 其他代码
return vnode
}
}
_render
関数は、render
実際にはvnode
、テンプレート コンパイルによって生成されたrender
関数を実行することによって生成される関数ですvnode
。
// src/core/instance/lifecycle.js
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()
if (prevEl) {
prevEl.__vue__ = null
}
if (vm.$el) {
vm.$el.__vue__ = vm
}
if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
vm.$parent.$el = vm.$el
}
}
_update
仮想 DOM を実際の DOM に変換するコア メソッドです. 主にpatch
このメソッド実際の DOM を作成します. レンダリングと更新の初期化時に渡されるパラメータのみが異なります.patch
メソッドは別の研究ノートに移動できます;
要約:
初期レンダリングのプロセスは、テンプレートがコンパイルされた後に実行されmountComponent
、mountComponent
主にインスタンスをマウントするvm._update(vm._render(), hydrating)
メソッドを実行され、_render
メソッドはテンプレートのコンパイルによって生成されたrender
関数をvnode
、_update
メソッドは生成された仮想 DOM を実際の DOM に変換します。 、主なコアはpatch
メソッド。