Vue 首次渲染源码
- 在初始化完结会调用 $mount 进行页面挂载
Vue.prototype._init = function (options?: Object) {
...
if (vm.$options.el) {
// 挂载页面
vm.$mount(vm.$options.el)
}
}
- 如果是带编译器的版本,会跳转到 $mount 的重写办法,多了将模板编译成 render 函数的操作, 详见
// # platforms/web/entry-runtime-with-compiler.js
Vue.prototype.$mount = function (){
...
// 调用 web/runtime/index.js 下定义的 $mount 办法
return mount.call(this, el, hydrating)
}
- 原始定义的 $mount 办法,解决了 el,并调用了 mountComponent
// # platforms/web/runtime/index.js
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
// 为什么这里 && 一下?// 如果带编译器版本,会重写 $mount 办法,此时 el 在重写办法内曾经初始化
// 如果不带编译器版本,浏览器环境下,须要把 el 转化成 dom,获取 dom.innerHTML 作为模板
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
- mountComponent 办法定义在 core/instance/lifecycle.js
mountComponent 办法解析
- 首先判断 如果开发模式没 render 函数,且应用运行时版本,则 template 模板会报错
- 而后执行 callHook(vm,’beforeMount’) 钩子
- 而后定义 updateComponent 办法,挂载操作的办法,(此处只是定义该办法并未执行)
updateComponent = () => {
// _render 调用用户传入的 render 或编译器生成的 render, 返回 VNode 虚构 dom
// _update 将虚构 dom 转为实在 dom
vm._update(vm._render(), hydrating)
}
- 调用 updateComponent 办法在 Watcher 实例中
new Watcher(vm, updateComponent, noop, {before () {if (vm._isMounted && !vm._isDestroyed) {callHook(vm, 'beforeUpdate')
}
}
}, true /* isRenderWatcher */)
- 最初执行 callHook(vm,”mounted”) 钩子
Watcher 类解析
- Watcher 类写在 core/observer/watcher.js
- 源码 watcher 类会调用三次 渲染 watcher(以后),计算属性 watcher,侦听器 watcher
- Watcher 类中定义很多属性,lazy 属性 true 用于计算属性 watcher
...
get(){
// 每个组件对应一个 watcher
// 如果组件有嵌套,先渲染外部组件,须要先把父组件 watcher 保存起来
pushTarget(this)
// 这里的 getter 就是 传入的 updataComponent
value = this.getter.call(vm, vm)
}
...
updateComponent 解析
- 此办法在 core/instance/lifecycle.js 下(之前注册的), 执行完则首次渲染结束
updateComponent = () => {
// 这是个回调,wather 外面会调用
// _render 或获取虚构 dom _update 将虚构 dom 转为实在 dom
vm._update(vm._render(), hydrating)
}