原理分析
1、$mounted
函数实际上调用的是mountComponent
函数,该函数首先判断是否存在render
函数,如果不存在,则给一个默认的渲染函数,该渲染函数会创建一个注释类型的VNode
节点,然后给出警告。
2、触发beforeMount
声明周期函数
3、定义updateComponent
函数,该函数内部首先执行render
渲染函数,得到一份最新的VNode
节点树,然后执行_update
方法对最新的Vnode
节点和上一次的VNode
节点进行对比,并更新DOM
元素(即patch
操作),完成一次渲染。这样子完成了挂载操作的一半工作。
4、另一半工作是开启对模板中的数据监控,当数据发生变化时,通知期其依赖进行视图更新。首先创建一个watcher
实例,并将定义好的updateComponent
函数作为第二个参数传入,watcher 构造函数的第二个参数支持 2 种类型,一种是数据路径,另外一种是函数。如果是数据路径,就会根据路径去读取这个数据,如果是函数,就会执行函数,一旦读取了数据或者执行了函数,就会触发数据的getter
方法,getter
方法会将watcher
实例添加到改数据的依赖列表中,,当数据发生变化时,就会通知依赖列表进行更新,当依赖接收到通知后,就会调用第四个参数回调函数去更新视图。文章来源:https://www.toymoban.com/news/detail-404944.html
换句话来说,updateComponent
函数所使用到的数据都会被watcher
监控,只要这些数据发生了变化,那么watcher
都将会得到通知,从而掉用第四个参数回调函数去更新视图文章来源地址https://www.toymoban.com/news/detail-404944.html
源码
// hydrating是跟服务端渲染相关的
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined;
return mountComponent(this, el, hydrating);
};
// $mount实际调用的是这个函数
export function mountComponent(
vm: Component,
el: ?Element,
hydrating?: boolean
): Component {
vm.$el = el;
// $mount最终需要的是render函数
if (!vm.$options.render) {
// 没有渲染函数的情况下会默认给一个渲染函数
vm.$options.render = createEmptyVNode;
// ...
}
// 触发beforeMount钩子函数
callHook(vm, "beforeMount");
let updateComponent;
if (process.env.NODE_ENV !== "production" && config.performance && mark) {
updateComponent = () => {
// ...
const vnode = vm._render();
vm._update(vnode, hydrating);
};
} else {
updateComponent = () => {
vm._update(vm._render(), hydrating);
};
}
// Watcher2个作用,一是初始化的时候执行回调函数,二是当vm实例中检测的数据发生变化就执行回调函数
// 渲染watcher
// 如果是渲染watcher,在初始化的时候会把vm._watcher赋值为watcher的实例
new Watcher(
vm,
updateComponent,
noop,
{
before() {
if (vm._isMounted && !vm._isDestroyed) {
// 如果数据发生了变化,并且组件在渲染状态并且没有销毁,触发beforeUpdate生命周期函数
callHook(vm, "beforeUpdate");
}
},
},
true /* isRenderWatcher */
);
hydrating = false;
// vm.$vnode:Vue 实例的父虚拟 Node,为null表示为根vue实例
if (vm.$vnode == null) {
// 根实例
vm._isMounted = true; // 标识已经挂载
callHook(vm, "mounted");
}
return vm;
}
// 把vnode渲染成真实的dom
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
const vm: Component = this;
const prevEl = vm.$el;
const prevVnode = vm._vnode;
const restoreActiveInstance = setActiveInstance(vm);
vm._vnode = vnode;
// Vue.prototype.__patch__ is injected in entry points
// based on the rendering backend used.
if (!prevVnode) {
// 没有旧prevVnode就是第一次渲染
vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);
} else {
// 更新
vm.$el = vm.__patch__(prevVnode, vnode);
}
restoreActiveInstance();
// update __vue__ reference
if (prevEl) {
prevEl.__vue__ = null;
}
if (vm.$el) {
vm.$el.__vue__ = vm;
}
if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
vm.$parent.$el = vm.$el;
}
};
到了这里,关于vue2源码(九)-- 挂载阶段的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!