Vue — mountComponent 挂载阶段
最后更新于:2022-04-02 08:12:47
>[success] # 挂载阶段
~~~
1.经过上个章节的分析$mount 有两个版本一个版本是'runtime only 版本的 Vue '对
在'src/platform/web/runtime/index.js',这个版本只能用render 函数,另一个版本
'runtime compiler'对应在'platforms\web\runtime-with-compiler.js' 边运行变将
'模板渲染'翻译成AST在转译成'render',即使是'runtime compiler'版本的$mount最后也都使用了
'runtime only 版本的 。
2.接下来Vue 要做的就是:函数被调用的时候就会渲染并且返回一个虚拟DOM的树。这个树非常轻量,
它的职责就是描述当前界面所应处的状态。当我们有了这个虚拟的树之后,再交给一个patch函数,
负责把这些虚拟DOM真正施加到真实的DOM上
3.接下来要做的就是生命周期这个部分
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/9e/ac/9eac1ac7684451cc3fd71623e6ca7ca4_929x446.png)
>[info] ## 分析 挂载阶段
~~~
1.因此最后即使你使用的是'函数渲染'版本vue也是将render 变成 虚拟dom过程,整个
分析就变成了'runtime only' 版本
~~~
>[danger] ##### runtime only 版本的 $mount
~~~
1.'runtime only' 版本$mount 代码很短,最后整个工作交给了'mountComponent'(挂载组件)
~~~
~~~
// wrap mount
Vue.prototype.$mount = function (
el?: any,
hydrating?: boolean
): Component {
return mountComponent(
this,
el && query(el, this.$document),
hydrating
)
}
~~~
>[danger] ##### mountComponent(挂载组件)
~~~
1.在下面的源码'mountComponent'函数的定义位于源码的'src/core/instance/lifecycle.js'中
2.下面代码做的事情:
2.1.判断实例上是否存在渲染函数,如果不存在,则设置一个默认的渲染函数createEmptyVNode,、
该渲染函数会创建一个注释类型的VNode节点
2.2.然后调用callHook函数来触发beforeMount生命周期钩子函数,beforeMount生命周期在这里触发。
这里就可以理解生命周期中说的,判断模板格式是否正确(2.1做了这个),也可以理解此时只是
render 函数并没有形成虚拟dom,也没有将页面内容真正渲染上
2.3.定义了'updateComponent',其中这个定义函数中参数'vm._render()'将会为我们得到一份最新的VNode
节点树,'如果调用了updateComponent函数,就会将最新的模板内容渲染到视图页面中'
2.4.接下来到了watcher 这部分,updateComponent函数作为第二个参数传给Watcher类从而创建了
watcher实例,那么updateComponent函数中读取的所有数据都将被watcher所监控
2.5挂载阶段才算是全部完成了,接下来调用挂载完成的生命周期钩子函数mounted
~~~
~~~
export function mountComponent (
vm: Component,
el: ?Element,
hydrating?: boolean
): Component {
vm.$el = el
if (!vm.$options.render) {
/*render函数不存在的时候创建一个空的VNode节点*/
vm.$options.render = createEmptyVNode
if (process.env.NODE_ENV !== 'production') {
/* istanbul ignore if */
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
)
}
}
}
/*触发beforeMount钩子*/
callHook(vm, 'beforeMount')
/*updateComponent作为Watcher对象的getter函数,用来依赖收集*/
let updateComponent
/* istanbul ignore if 一些埋点操作 省略掉了*/
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
......
} else {
updateComponent = () => {
vm._update(vm._render(), hydrating)
}
}
/*这里对该vm注册一个Watcher实例,Watcher的getter为updateComponent函数,
用于触发所有渲染所需要用到的数据的getter,进行依赖收集,该Watcher实例会存在所有
渲染所需数据的闭包Dep中*/
vm._watcher = new Watcher(vm, updateComponent, noop)
hydrating = false
// manually mounted instance, call mounted on self
// mounted is called for render-created child components in its inserted hook
if (vm.$vnode == null) {
/*标志位,代表该组件已经挂载*/
vm._isMounted = true
/*调用mounted钩子*/
callHook(vm, 'mounted')
}
return vm
}
~~~
';