# vue 实例挂载
# 获取 render
思路:vue 只认 render 函数,如果存在 render 函数直接使用,如果 render 函数不存在,找到 template 把 template 编译成 render 函数。
//缓存了原型上的 $mount 方法
const mount = Vue.prototype.$mount
//重新定义mount方法
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && query(el)
//vue不能直接挂在body或者html上
/* istanbul ignore if */
if (el === document.body || el === document.documentElement) {
process.env.NODE_ENV !== 'production' && warn(
`Do not mount Vue to <html> or <body> - mount to normal elements instead.`
)
return this
}
const options = this.$options
// resolve template/el and convert to render function
//如果没有定义render方法
if (!options.render) {
//获取到template字符串
let template = options.template
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 = getOuterHTML(el)
}
if (template) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile')
}
//compileToFunctions 把template转化为render方法
const { render, staticRenderFns } = compileToFunctions(template, {
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this)
options.render = render
options.staticRenderFns = staticRenderFns
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile end')
measure(`vue ${this._name} compile`, 'compile', 'compile end')
}
}
}
//调用原型本身的mount挂载方法
return mount.call(this, el, hydrating)
}
# $mount 把 render 函数挂载
$mount 方法支持传入 2 个参数,
- 第一个是 el,它表示挂载的元素,可以是字符串,也可以是 DOM 对象,如果是字符串在浏览器环境下会调用 query 方法转换成 DOM 对象的。
- 第二个参数是和服务端渲染相关,在浏览器环境下我们不需要传第二个参数。
$mount 方法实际上会去调用 「mountComponent」 方法(完成整个渲染过程)
mountComponent 核心就是先调用 vm._render 方法先生成虚拟 Node,再实例化一个渲染 Watcher,在它的回调函数中会调用 updateComponent 方法,最终调用 vm._update 更新 DOM。Watcher 在这里起到两个作用,一个是初始化的时候会执行回调函数,另一个是当 vm 实例中的监测的数据发生变化的时候执行回调函数,这块儿我们会在之后的章节中介绍。函数最后判断为根节点的时候设置 vm._isMounted 为 true,表示这个实例已经挂载了,同时执行 mounted 钩子函数。这里注意 vm.$vnode 表示 Vue 实例的父虚拟 Node,所以它为 Null 则表示当前是根 Vue 的实例。