在vue的内部封装了大量的api和方法供开发者调用,$mount方法是其中之一:
用法:
vm.$mount( [elementOrSelector] )
参数:
{Element | string} [elementOrSelector]
{boolean} [hydrating]
作用:
- 如果
Vue
实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可以使用vm.$mount()
手动地挂载一个未挂载的实例。 - 如果没有提供
elementOrSelector
参数,模板将被渲染为文档之外的的元素,并且你必须使用原生DOM API
把它插入文档中。 - 这个方法返回实例自身,因而可以链式调用其它实例方法。
var mount = Vue.prototype.$mount;
Vue.prototype.$mount = function (el,hydrating) {
el = el && query(el);
if (el === document.body || el === document.documentElement) {
warn(
"Do not mount Vue to <html> or <body> - mount to normal elements instead."
);
return this
}
var options = this.$options;
// resolve template/el and convert to render function
if (!options.render) {
var template = options.template;
if (template) {
if (typeof template === 'string') {
if (template.charAt(0) === '#') {
template = idToTemplate(template);
/* istanbul ignore if */
if (!template) {
warn(
("Template element not found or is empty: " + (options.template)),
this
);
}
}
} else if (template.nodeType) {
template = template.innerHTML;
} else {
{
warn('invalid template option:' + template, this);
}
return this
}
} else if (el) {
template = getOuterHTML(el);
}
if (template) {
if (config.performance && mark) {
mark('compile');
}
var ref = compileToFunctions(template, {
outputSourceRange: "development" !== 'production',
shouldDecodeNewlines: shouldDecodeNewlines,
shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this);
var render = ref.render;
var staticRenderFns = ref.staticRenderFns;
options.render = render;
options.staticRenderFns = staticRenderFns;
if (config.performance && mark) {
mark('compile end');
measure(("vue " + (this._name) + " compile"), 'compile', 'compile end');
}
}
}
return mount.call(this, el, hydrating)
};
从源码中可以看到,在vue的实例上挂$mount方法之前,做了一次缓存$mount。这是因为vue的俩个版本造成的,还记得吗,一个是完整版,一个是运行时版本,他们的区别就是有没有模版编译,所以,$mount也就有两个版本,最开始的缓存就是为了,缓存运行时的$mount。下面我们来细看$mount内部是怎么实现的。
从代码中可以看到,该函数可大致分为三部分:
- 根据传入的
el
参数获取DOM
元素; - 在用户没有手写
render
函数的情况下获取传入的模板template
; - 将获取到的
template
编译成render
函数;
首先,根据传入的el获取dom元素,并判断其不是body或者html,这是因为body或者html替换后会破坏html文档结构。
其次,在用户没有手写render
函数的情况下获取传入的模板template。
首先获取用户传入的template
选项赋给变量template
,如果变量template
存在,则接着判断如果template
是字符串并且以##
开头,则认为template
是id
选择符,则调用idToTemplate
函数获取到选择符对应的DOM
元素的innerHTML
作为模板。如果template
不是字符串,那就判断它是不是一个DOM
元素,如果是,则使用该DOM
元素的innerHTML
作为模板,如果既不是字符串,也不是DOM
元素,此时会抛出警告:提示用户template
选项无效。如果变量template
不存在,表明用户没有传入template
选项,则根据传入的el
参数调用getOuterHTML
函数获取外部模板,不管是从内部的template
选项中获取模板,还是从外部获取模板,总之就是要获取到用户传入的模板内容,有了模板内容接下来才能将模板编译成渲染函数。获取到模板之后,接下来要做的事就是将其编译成渲染函数,把模板编译成渲染函数是在compileToFunctions
函数中进行的,该函数接收待编译的模板字符串和编译选项作为参数,返回一个对象,对象里面的render
属性即是编译好的渲染函数,最后将渲染函数设置到$options
上。
这就是$mount函数的实现过程。