如果你需要在客户端编译模板 (比如传入一个字符串给 template 选项,或挂载到一个元素上并以其 DOM 内部的 HTML 作为模板),就将需要加上编译器,即完整版
当使用 vue-loader 或 vueify 的时候,*.vue 文件内部的模板会在构建时预编译成 JavaScript。你在最终打好的包里实际上是不需要编译器的,所以只用运行时版本即可— 官方文档
客户端编译模板
1 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> 2 3 <div id="app"></div> 4 5 <script> 6 new Vue({ 7 el: ‘#app‘, 8 data: { 9 message: ‘Hello Vue!‘ 10 }, 11 template: ‘<div>{{ message }}</div>‘ 12 }) 13 </script>
这种用法就需要在客户端(即浏览器中)编译模板,模版的内容是 <div>{{ message }}</div> ,模版的数据是 message: ‘Hello Vue!‘ 。
因此,如果使用 script 引入只有运行时版本的vue.js vue.runtime.js ,就会报错:
vue.runtime.js:593 [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.
使用渲染函数
1 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.runtime.js"></script> 2 3 <div id="app"></div> 4 5 <script> 6 new Vue({ 7 el: ‘#app‘, 8 data: { 9 message: ‘Hello Vue!‘ 10 }, 11 render (createElement) { 12 return createElement(‘div‘, this.message) 13 } 14 }) 15 </script>
这种用法就是直接给出渲染函数来进行内容输出(具体 createElement 语法后面再讲),这种情况下不需要进行客户端渲染,直接引用运行时版本的vue.js即可,并不会报错。
预编译模板
简单的页面结构我们可以直接通过 createElement 函数来手动编写,但是对于复杂的页面结构呢?vue提供了 Vue.compile 函数用于将模版编译成 render 函数,示例如下:
1 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> 2 3 <script> 4 const result = Vue.compile(‘<div>{{ message }}</div>‘); 5 console.log(result.render); 6 </script>
注意:只有 Runtime + Compiler 版本的vuejs才有 Vue.compile 函数,运行时版本的vue.js是没有这个函数的,所以这里也就是所谓的预编译。
输出的结果如下:
1 ƒ anonymous( 2 ) { 3 with(this){return _c(‘div‘,[_v(_s(message))])} 4 }
我们用预编译生成的render
函数替代上一章的 render 函数:
1 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.runtime.js"></script> 2 3 <div id="app"></div> 4 5 <script> 6 new Vue({ 7 el: ‘#app‘, 8 data: { 9 message: ‘Hello Vue!‘ 10 }, 11 render (createElement) { 12 with(this){return _c(‘div‘,[_v(_s(message))])} 13 } 14 }) 15 </script>
可以看到这种“开发时预编译,上线使用运行时”的方式既满足了开发需要又减少了线上文件的大小。
注:通过打印,可以看到 createElement 以及 this._c , this._v 和 this._s 的值:
1 render (createElement) { 2 console.log(createElement, this._c, this._v, this._s) 3 with(this){return _c(‘div‘,[_v(_s(message))])} 4 } 5 ƒ (a, b, c, d) { return createElement(vm, a, b, c, d, true); } 6 ƒ (a, b, c, d) { return createElement(vm, a, b, c, d, false); } 7 ƒ createTextVNode (val) {...} 8 ƒ toString (val) {...}
所以可以看出,我们最开始手写的渲染函数 return createElement(‘div‘, this.message) 只是上面预编译生成的一个简版。
基于 HTML 的模板语法
除了上面几种基于js代码的形式来创建模版,vuejs也支持基于 HTML 的模板语法,用法如下:
1 <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script> 2 </head> 3 <body> 4 <div id="app"><div>{{ message }}</div></div> 5 6 <script> 7 new Vue({ 8 el: ‘#app‘, 9 data: { 10 message: ‘Hello Vue!‘ 11 } 12 }) 13 </script>
注意,这种写法也必须要使用 Runtime + Compiler 版本的vuejs才可以允许,因为其实质上还是在客户端进行模版编译,因为上面的写法实质上等同于下面的写法:
1 <div id="app"></div> 2 <template id="tpl"> 3 <div>{{ message }}</div> 4 </template> 5 6 <script> 7 new Vue({ 8 el: ‘#app‘, 9 data: { 10 message: ‘Hello Vue!‘ 11 }, 12 template: ‘#tpl‘ 13 }) 14 </script>
vuejs源码中的 template 解析
在vuejs源码中,关于获取 template 的关键代码如下:
1 var template = options.template; 2 if (template) { 3 if (typeof template === ‘string‘) { 4 if (template.charAt(0) === ‘#‘) { 5 template = idToTemplate(template); 6 } 7 } else if (template.nodeType) { 8 template = template.innerHTML; 9 } else { 10 { 11 warn(‘invalid template option:‘ + template, this); 12 } 13 return this 14 } 15 } else if (el) { 16 template = getOuterHTML(el); 17 }
逻辑主要步骤如下:
- 先判断是否有 template 属性
- 如果没有,则直接通过 el 中的 html 代码作为模版
- 如果有,判断是否是字符串(非字符串的形式暂不讨论)
- 是字符串的情况下,是否以
#
字符开头 - 如果是,则获取对应id的 innerHTML 作为模版
- 如果不是以
#
字符开头,则直接作为作为模版
总结
一句话来讲就是:如果有 render 函数就可以使用运行时版本的vuejs,否则必须使用 Runtime + Compiler 版本的vuejs。
原文地址:https://www.cnblogs.com/joyco773/p/11657503.html