打包入口文件
扩展$mount,处理el和template
// platforms/web/entry-runtime-with-compiler.js
Vue.prototype.$mount = function () {
const options = this.$options;
// 如果没有render函数选项,则将template/el的设置转为render
if (!options.render) {
if (options.template) {
// 解析template
} else if (el) {
// 否则解析el选项
template = getOuterHTML(el);
}
if (template) {
const { render, staticRenderFns } = compileToFunctions(
template,
{
outputSourceRange: process.env.NODE_ENV !== "production",
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments,
},
this,
);
options.render = render;
}
}
};
- 从上面代码可知
当
render/template/el
同时存在时,render>template>el
web运行时代码
1. 实现$mount
// platforms/web/runtime/index.js
Vue.prototype.$mount = function () {
return mountComponent(this, el, hydrating);
};
// src/core/instance/lifecycle.js
function mountComponent() {
callHook(vm, "beforeMount");
// 组件的跟新函数
updateComponent = () => {
// vm._render()得到虚拟dom
vm._update(vm._render(), hydrating);
};
// 在 Watcher实例中做组件更新 updateComponent
// vue2中一个组件对应一个Watcher实例
new Watcher(
vm,
updateComponent,
noop,
{
before() {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, "beforeUpdate");
}
},
},
true /* isRenderWatcher */,
);
if (vm.$vnode == null) {
vm._isMounted = true;
callHook(vm, "mounted");
}
return vm;
}
Watcher
// src/core/observer/watcher.js
class Watcher {
// expOrfn: 可能是表达式,函数
constructor(vm, expOrFn, cb) {
this.vm = vm;
if (typeof expOrFn === "function") {
this.getter = expOrFn; // 上面传进来的是函数
}
this.get();
}
get() {
pushTarget(this); // 当前watcher保存到Dep中 src/core/observer/dep.js
const vm = this.vm;
this.getter.call(vm, vm); // 执行刚才的updateComponent
}
addDep(dep) {
const id = dep.id;
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id);
this.newDeps.push(dep); // watcher中添加dep
if (!this.depIds.has(id)) {
dep.addSub(this); // dep中添加watcher
}
}
}
}
2. Vue.prototype.patch = inBrowser ? patch : noop
patch: dom diff
core/index.js
import Vue from "./instance/index";
initGlobalAPI(Vue); // 全局API实现 ./global-api/index'
实例入口
// core/instance/index.js
function Vue() {
this._init();
}
initMixin(Vue);
stateMixin(Vue);
eventsMixin(Vue);
lifecycleMixin(Vue);
renderMixin(Vue);
initMixin
// core/instance/init.js
function initMixin(Vue) {
Vue.prototype._init = function () {
// 选项合并
vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), options || {}, vm);
initLifecycle(vm); // 初始化实例属性 $parent\$children\$root
initEvents(vm); // 初始化组件自定义事件
initRender(vm); // 插槽解析$slots, _c/$createElements
callHook(vm, "beforeCreate");
initInjections(vm); // resolve injections before data/props
initState(vm); // 初始化 props、methods、data、computed、watch
initProvide(vm); // resolve provide after data/props
callHook(vm, "created");
};
}