Vue有三个属性和模板有关,官网上是这样解释的:
el ;提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标
template ;一个字符串模板作为 Vue 实例的标识使用。模板将会 替换 挂载的元素。挂载元素的内容都将被忽略,除非模板的内容有分发插槽。
render ;字符串模板的代替方案,允许你发挥 java script 最大的编程能力。该渲染函数接收一个 createElement
方法作为第一个参数用来创建 VNode
。
简单说一下,就是:
Vue内部会判断如果没有render属性则把template属性的值作为模板,如果template不存在则把el对应的DOM节点的outerHTML属性作为模板,经过一系列正则解析和流程生成一个render函数,最后通过with(this){}来执行。
也就是说template的优先级大于el。
render的参数是Vue内部的$createElement函数(位于4486行),它的可扩展性更强一些,在一些项目的需求中,可以用很简单的代码得到一个模板。例如Vue实战9.3里介绍的例子,有兴趣可以看看
render可以带3个参数,分别如下:
tag ;元素的标签名,也可以是组件名
data ;该VNode的属性,是个对象
children ;子节点,是个数组
其中参数2可以省略的,在4335行做了修正,最后执行_createElement()函数,如下:
function createElement ( //第4335行 context, tag, data, children, normalizationType, alwaysNormalize ) { if (Array.isArray(data) || isPrimitive(data)) { //如果data是个数组或者是基本类型 normalizationType = children; children = data; //修正data为children data = undefined; //修正data为undefined } if (isTrue(alwaysNormalize)) { normalizationType = ALWAYS_NORMALIZE; } return _createElement(context, tag, data, children, normalizationType) //最后执行_createElement创建一个虚拟VNode }
例如下面三个Vue实例,分别用el、template和rentder指定模板,它们的输出是一样的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <script src="https://cdn.bootcss.com/vue/2.5.16/vue.js"></script> <title>Document</title> </head> <body> <div id="app1">{{message}}</div> <div id="app2"></div> <div id="app3"></div> <script> var data={message:'you are so annoying'} new Vue({el:'#app1',data}) //用el做模板 new Vue({el:'#app2',data,template:"<div>{{message}}</div>"}) //用template做模板 new Vue({el:'#app3',data,render:function(h){return h('div',this.message)}}) //直接用render函数指定模板 </script> </body> </html>
、浏览器显示结果:
可以看到输出是一摸一样的
Vue实例后会先执行_init()进行初始化,快结束时会判断是否有el属性,如果存在则调用$mount进行挂载,$mount函数如下:
Vue.prototype.$mount = function ( //定义在10861行 el, hydrating ) { el = el && query(el); /* istanbul ignore if */ if (el === document.body || el === document.documentElement) { "development" !== 'production' && 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) { //如果render属性不存在 var template = options.template; //则尝试获取template属性并将其编译成render if (template) { if (typeof template === 'string') { if (template.charAt(0) === '#') { template = idToTemplate(template); /* istanbul ignore if */ if ("development" !== 'production' && !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,