Vue 源码解读-2.6.11
Vue 基础原理
前言:哥哥教你 断点学习下
new Vue 做了什么
各种初始化
初始化流程 | 描述 |
---|---|
initLifecycle | 初始化生命周期 |
initEvents | 事件 |
initRender | render 渲染函数 |
callHook(vm, ‘beforeCreate’); | |
initInjections | resolve injections before data/props |
initState | 初始化 props,data,method,computed,watch |
initProvide | resolve provide after data/props |
callHook(vm, ‘created’) |
Vue.prototype._init = function (options) {
var vm = this;
// a uid
vm._uid = uid$3++;
var startTag, endTag;
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
startTag = "vue-perf-start:" + (vm._uid);
endTag = "vue-perf-end:" + (vm._uid);
mark(startTag);
}
// a flag to avoid this being observed
vm._isVue = true;
// merge options
if (options && options._isComponent) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
initInternalComponent(vm, options);
} else {
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
);
}
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
initProxy(vm);
} else {
vm._renderProxy = vm;
}
// expose real self
vm._self = vm;
initLifecycle(vm);
initEvents(vm);
initRender(vm);
callHook(vm, 'beforeCreate');
initInjections(vm); // resolve injections before data/props
initState(vm);
initProvide(vm); // resolve provide after data/props
callHook(vm, 'created');
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
vm._name = formatComponentName(vm, false);
mark(endTag);
measure(("vue " + (vm._name) + " init"), startTag, endTag);
}
if (vm.$options.el) {
vm.$mount(vm.$options.el);
}
};
初始化 $mount("#app") 做了什么
绑定部分生命周期,挂载DIV
第一步:找到挂载div 绑定
第二部:mountComponent 绑定 render 同时 callhook beforeMount,
第三部:Watcher 对象 render 同时监听渲染 callHook(vm, ‘beforeUpdate’);
第四部:callHook(vm, ‘mounted’);
function mountComponent ( vm, el, hydrating ) {
vm.$el = el;
if (!vm.$options.render) {
vm.$options.render = createEmptyVNode;
if (process.env.NODE_ENV !== 'production') {
...
}
callHook(vm, 'beforeMount');
var updateComponent;
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
updateComponent = function () {
var name = vm._name;
var id = vm._uid;
var startTag = "vue-perf-start:" + id;
var endTag = "vue-perf-end:" + id;
mark(startTag);
var vnode = vm._render();
mark(endTag);
measure(("vue " + name + " render"), startTag, endTag);
mark(startTag);
vm._update(vnode, hydrating);
mark(endTag);
measure(("vue " + name + " patch"), startTag, endTag);
};
} else {
updateComponent = function () {
vm._update(vm._render(), hydrating);
};
}
new Watcher(vm, updateComponent, noop, {
before: function before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate');
}
}
}, true /* isRenderWatcher */);
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;
callHook(vm, 'mounted');
}
return vm
}
衍生问题:
document.getElementById 和 document.querySelector 区别
data 值是怎么绑定的呢
在项目初始化的时候 对data 数据进行 判断
:注意 不能和methods 种的函数 props 由重复
使用 Object.defineProperty 来进行数据绑定监听
data 的值是怎么 在dom 中进行动态变化的
首先 vue 文件被解析成对象VNode ,在对象里面获取 data 中的值
在数据变化后 (set 后)会dep.notify() 通知所有依赖的watch 进行update更新
update 时会重新render
通过 新的 Vnode 进行对比 然后 替换 重新生成 el
由兴趣可以跟踪一下 patch 这个方法 ,很有意思
这里有个东西 需要注意 虚拟Dom 这些事件是绑定在虚拟dom 上面 简单来说,绑定事件的时候Dom还没有注入的 body 里面
事件绑定是怎么实现的
同上一样 ,我们的所有绑定之初都是在 VNode 的基础上 去进行绑定保存的
但是 el 上面的绑定是在 createElement 上面绑定的
具体而言
在chorme 中找到绑定事件 然后向上查找
发现是通过 updateListeners 这方法 再往上走
发现是通过 updateDOMListeners 再网上
发现是通过invokeCreateHooks再网上
发现是通过createElm再网上
发现是通过 patch(不一定是在更新的时候哈,主要是因为 data 变化的时候会触发 更新 ,和我测试的环境有关,一般情况到 createElm 就可以了)
事件是怎么绑定在 html 的标签上面的 (在Vnode 里面的elm )
差点 看错了, 在我的理解中虚拟dom 是干净的 没有污染的 随时可以 注入 html 里面的
具体 一般是在createdElm 创建的 dom 元素 包括 attr prop addEvent 等。。。然后回挂上 vnode
衍生 问题
为什么要用虚拟Dom
- 虚拟dom 不依赖环境 全是 js 对象,可以做到跨平台
- js 执行效率相对 直接操作dom 要更加高效
- 可以使用diff 方法进行局部最小化更新 不影响其他dom ,即:操作dom 最小化