Vue 源码
你想要的 vue 源码分析 · 04
vue $mount 的实现 vue 中是通过$mount 实例方法挂载 vm, 本质是把 template 和 el 转成 render 方法 转成 render 方法后,执行 mountComponent 本质是一个 new Watcher 的实现,当 vm 实例中监测到的数据发生变化的时候执行 updateComponent,进而渲染出 vm._render(vnode)
vue $mount 的实现 vue 中是通过$mount 实例方法挂载 vm, 本质是把 template 和 el 转成 render 方法 转成 render 方法后,执行 mountComponent 本质是一个 new Watcher 的实现,当 vm 实例中监测到的数据发生变化的时候执行 updateComponent,进而渲染出 vm._render(vnode)
vue 中是通过$mount 实例方法挂载 vm,
compiler 版本的 \$monut 实现本质是把 template 和 el 转成 render 方法
// src/platform/web/entry-runtime-with-compiler.js
// 先把 $mount缓存起来
const mount = Vue.prototype.$mount;
// 然后重新定义
Vue.prototype.$mount = function(el?: string | Element, hydrating?: boolean): Component {
// el既可以是字符穿也可以是dom对象
el = el && query(el);
// 对el进行限制,不能挂载在html和body这样的根节点上
if (el === document.body || el === document.documentElement) {
process.env.NODE_ENV !== 'production' && warn(`Do not mount Vue to <html> or <body> - mount to normal elements instead.`);
return this;
}
const options = this.$options;
// 如果没有定义render方法,会把el或template转换成render方法
if (!options.render) {
let template = options.template;
// template存在
if (template) {
if (typeof template === 'string') {
if (template.charAt(0) === '#') {
template = idToTemplate(template);
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !template) {
warn(`Template element not found or is empty: ${options.template}`, this);
}
}
} else if (template.nodeType) {
template = template.innerHTML;
} else {
if (process.env.NODE_ENV !== 'production') {
warn('invalid template option:' + template, this);
}
return this;
}
} else if (el) {
// template不存在,获取到outHTML
template = getOuterHTML(el);
}
// 编译相关
if (template) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile');
}
// compileToFunctions是一个在线编译的过程
const { render, staticRenderFns } = compileToFunctions(
template,
{
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
},
this
);
// render函数
options.render = render;
// 静态render元素
options.staticRenderFns = staticRenderFns;
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile end');
measure(`vue ${this._name} compile`, 'compile', 'compile end');
}
}
}
// 调用原先$mount方法挂载
return mount.call(this, el, hydrating);
};
runtime $mount实现方式转成 render 方法后,执行 mountComponent
// src\platforms\web\runtime\index.js
// $mount支持两个参数,第一个是el,第二个是服务端渲染相关
Vue.prototype.$mount = function(el?: string | Element, hydrating?: boolean): Component {
el = el && inBrowser ? query(el) : undefined;
return mountComponent(this, el, hydrating);
};
mountComponent的实现本质是一个 new Watcher 的实现,当 vm 实例中监测到的数据发生变化的时候执行 updateComponent,进而渲染出 vm._render(vnode)
// src/core/instance/lifecycle.js
export function mountComponent(vm: Component, el: ?Element, hydrating?: boolean): Component {
vm.$el = el;
// 如果render不存在,或者template编译不成功
if (!vm.$options.render) {
vm.$options.render = createEmptyVNode;
if (process.env.NODE_ENV !== 'production') {
// 报一个警告:如果用了runtime only编译方法,又写了template了,就会报了警告
if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') || vm.$options.el || el) {
warn('You are using the runtime-only build of Vue where the template ' + 'compiler is not available. Either pre-compile the templates into ' + 'render functions, or use the compiler-included build.', vm);
} else {
// 报一个警告:如果用了runtime only编译方法,没有template或者render函数
warn('Failed to mount component: template or render function not defined.', vm);
}
}
}
callHook(vm, 'beforeMount');
let updateComponent;
// 性能埋点
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
updateComponent = () => {
const name = vm._name;
const id = vm._uid;
const startTag = `vue-perf-start:${id}`;
const endTag = `vue-perf-end:${id}`;
mark(startTag);
const 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 = () => {
// 渲染出vnode
vm._update(vm._render(), hydrating);
};
}
// we set this to vm._watcher inside the watcher's constructor
// since the watcher's initial patch may call $forceUpdate (e.g. inside child
// component's mounted hook), which relies on vm._watcher being already defined
// 初始化的时候执行回调函数
// 当vm实例中监测到的数据发生变化的时候执行updateComponent
new Watcher(
vm,
updateComponent,
noop,
{
before() {
if (vm._isMounted) {
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;
}
暂无评论
确认操作
请再次确认编辑图片
待上传图片 (剩余 0 张)
项目详情
确认评论邮箱
邀请制评论