原文鏈接我的blog,歡迎STAR。
在上篇里,我們已經(jīng)分析了在 main.js 可以通過(guò)el屬性設(shè)置掛載點(diǎn),又可以通過(guò)手動(dòng)設(shè)置 vm.$mount()。在這篇,我們深入底層,了解原理。
老規(guī)矩,我們先分享一篇文章 Vue.js 源碼學(xué)習(xí)筆記。
這篇文章里反復(fù)提到了compile, 額....(什么鬼?手動(dòng)攤手。)
查 Vue,官網(wǎng)文檔, 原來(lái)Vue模板編譯成render函數(shù)的過(guò)程叫做 compile。
現(xiàn)在入正題:
在 _init, 文件里,有一條重要的線索:
在 _init 的最后,會(huì)運(yùn)行 initRender 方法,在這個(gè)方法中,如果el屬性存在,既是運(yùn)行vm.$mount(vm.$options.el),掛載一個(gè)未掛載的實(shí)例。如果不存在,既是已經(jīng)通過(guò)vm.$mount()手動(dòng)地掛載一個(gè)未掛載的實(shí)例。
接下來(lái),我們找到 vm.$mount() 方法,
源碼上分析:
// 如果options.render 存在,直接運(yùn)行mount方法
// 如果不存在時(shí)
if (!options.render) {
let template = options.template
// 如果template模板存在,獲取template參數(shù)作為模板
if (template) {
if (typeof template === 'string') {
if (template.charAt(0) === '#') {
template = idToTemplate(template)
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !template) {
warn(
`Template element not found or is empty: ${options.template}`,
this
)
}
}
} else if (template.nodeType) {
template = template.innerHTML
} else {
if (process.env.NODE_ENV !== 'production') {
warn('invalid template option:' + template, this)
}
return this
}
} else if (el) {
// 如果template不存在,且el存在
// 則獲取template的outHTML作為模板
template = getOuterHTML(el)
}
// 如果template模板存在,則調(diào)用compileToFunctions, 轉(zhuǎn)化為render
if (template) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile')
}
const { render, staticRenderFns } = compileToFunctions(template, {
shouldDecodeNewlines,
delimiters: options.delimiters
}, this)
options.render = render
options.staticRenderFns = staticRenderFns
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile end')
measure(`${this._name} compile`, 'compile', 'compile end')
}
}
}
return mount.call(this, el, hydrating)
從這段源碼里,我們也能夠很直觀的得到以前的一個(gè)結(jié)論,Vue 2.0中的模板有三種引用寫(xiě)法:el, template, render。其中的優(yōu)先級(jí)是 render > template > el。
當(dāng)完成 compileToFunctions() 將模板轉(zhuǎn)化為 render 以后,會(huì)開(kāi)始 mount 方法。
在mount方法里,
vm._watcher = new Watcher(vm, updateComponent, noop)
updateComponent = () => {
vm._update(vm._render(), hydrating)
}
轉(zhuǎn)了一圈,其實(shí)又回到了從render函數(shù),返回 vnode 的部分,這里我們?cè)诘谌呀?jīng)詳解,不再重復(fù)。
完。