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)
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。