vue.js 是完整的版本包含了模板编译函数,通过查看vue.js源码发现,当使用完整版本的vue.js 时,调用$mount
函数进行挂载的时候,$mount
函数调用的是入下函数:
Vue.prototype.$mount = function (
el,
hydrating
) {
//query会根据el去查询要挂载到的节点,如果传的是字符串,类似dom元素的id、css类名或者元素类型如P div等等
el = el && query(el);
/* istanbul ignore if */
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) {
/* istanbul ignore if */
if (config.performance && mark) {
mark('compile');
}
//模板编译函数,可以编译模板,生成一个render函数
var ref = compileToFunctions(template, {
outputSourceRange: "development" !== 'production',
shouldDecodeNewlines: shouldDecodeNewlines,
shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this);
//生成的render函数
var render = ref.render;
var staticRenderFns = ref.staticRenderFns;
options.render = render;
options.staticRenderFns = staticRenderFns;
/* istanbul ignore if */
if (config.performance && mark) {
mark('compile end');
measure(("vue " + (this._name) + " compile"), 'compile', 'compile end');
}
}
}
return mount.call(this, el, hydrating)
};
完全版本可包含了模板编译函数,在上面的代码中通过调用compileToFunctions
函数对模板进行编译然后生成了一个匿名的render函数,主要用是通过new Function(code)
对一个函数的字符串描述形式生成一内部匿名个函数。compileToFunctions
函数挂载到了Vue上面,可以通过Vue.compile
进行直接调用进行模板编译。
示例代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app">
<div>{{message}}</div>
</div>
<script>
console.log(Vue.compile(document.querySelector("#app").outerHTML).render);
</script>
</body>
</html>
编译结果如下
ƒ anonymous()
{
with (this) {
return _c('div', {attrs: {"id": "app"}}, [_c('div', [_v(_s(message))])])
}
}
所以完整版本的vue.js 库包含了模板编译的功能,在内部会调用模板编译函数生成一个匿名的render函数。
而vue.runtime.js版本不包含模板编译函数,所以使用该版本的库时,必须自己实现render函数,不然就会报错。
vue.runtime.js 库的$mount
函数定义如下:
Vue.prototype.$mount = function (
el,
hydrating
) {
el = el && inBrowser ? query(el) : undefined;
return mountComponent(this, el, hydrating)
};
而mountComponent
定义如下;
function mountComponent (
vm,
el,
hydrating
) {
vm.$el = el;
if (!vm.$options.render) {
vm.$options.render = createEmptyVNode;
{
/* istanbul ignore if */
//如果不包含render函数则会抛出如下错误
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 {
warn(
'Failed to mount component: template or render function not defined.',
vm
);
}
}
}
callHook(vm, 'beforeMount');
var updateComponent;
/* istanbul ignore if */
if (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);
};
}
// 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
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
}
如果以如下方式进行调用的话
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.runtime.js"></script>
</head>
<body>
<div id="app">
<div>{{message}}</div>
</div>
<script>
let app= new Vue({
data:{
message:"er",
}
});
app.$mount("#app")
</script>
</body>
</html>
则会抛出如下错误,因为vue.runtime.js缺少模板编译函数,不会再内部生成render函数。
[Vue 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.
当使用vue.runtime.js版本时必须自己实现render函数,如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="vue.runtime.js"></script>
</head>
<body>
<div id="app">
<div>{{message}}</div>
</div>
<script>
let app = new Vue({
data: {
message: "er",
},
render(c) {
return c('div', {
'attrs': {
'id':'#app',
},
},[this._v(this._s(this.message))])
}
});
app.$mount("#app")
</script>
</body>
</html>