首先新建一个空的 Vue 项目,我们会在 main.js 文件中发现如下代码
import Vue from 'vue'
import App from './App.vue'
// 关闭vue的生产提示
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
$mount('#app') :可以参考之前的博文 el与data的两种写法,这里就不做过多解释
其中有一个 render 函数,而且这个函数写的很奇怪,完全看不懂。如果按照我之前的理解,我觉得这个代码可能是这样的
new Vue({
// template 渲染组件
template: ` `,
// components 注册组件
components: {
App,
},
}).$mount("#app");
代码改成这样编译运行之后,在浏览器上并没有展现出我们希望的效果,而是在控制台报了一个错
这个错误翻译过来就是:您正在使用Vue的仅运行时构建,其中模板编译器不可用。要么将模板预编译为呈现函数,要么使用包含编译器的构建。
理解一下,报错的意思就是,无法编译模板 templete ,要么将模板改为 render 函数,要么使用带有编译器的Vue
在官网上存在这么一个例子,说的比较清楚,按照之前的理解,我使用 templete 模板是没有问题的,但是 因为 脚手架生成的项目,引入的 Vue 文件,是不带 templete 模板编译器的 运行时文件,所以导致出现了这个问题。
验证这个问题可以按照如下方式:可以在 node_modules 包中找到当前的 Vue 包,然后点开 package.json 文件,可以看到 module 的路径是 运行时的 vue.js 文件,module 所暴露的路径,就是我们通过 import 引入时候的文件路径
如果你还是想验证一下,到底是不是这个文件,那我们在文件里面 console 一下。
重启项目之后,在 chrome 控制台上看输出,说明确实引入的是 运行时 的vue.js
而官网上也明确说明了
想要解决这个问题也很简单,因为我们是通过脚手架生成的项目,脚手架引入的是不带模板编译的Vue 文件,那我们引入一个完整版的 Vue.js 文件来试试。至于 render 方法,我们稍后再说。
// import Vue from 'vue'
// 运行时的文件路径也是在 dist 目录下,只是package.json 里面 的 module 直接 暴露了运行时的文件,我们想要完整的 vue.js 也直接去 dist 目录下找就行了
import Vue from 'vue/dist/vue'
重启项目,你会发现页面完全正常了,就和之前 脚手架 新建项目展示的完全一样。
但是,问题来了,为什么脚手架创建的项目,会自动给我们引入这个 运行时 的 vue.js 包呢?为啥不引入完整版的呢?为啥不能 使用 templete 而要使用 render 呢?
render
首先,我们注释掉 脚手架生成的 render 函数 ,因为这玩意也看不懂,干脆自己写一个空的 render 函数。
new Vue({
el:'#app'
render() {},
components: {
App,
},
})
这么写起来,在博文里面看起来一切正常,但是在编辑器里面,这玩意可就报错啦。
render 函数 直接报错,且 ts检测之后提示,render 函数 需要有一个返回值,如果不带返回值,直接保存运行代码,页面上长啥样呢?
直接报错,且错误提示就是 ts 给出的提示。
脚手架的 render 函数,传了一个参数,打印一下,看看这个参数是个啥
首先,该参数是一个函数,且接收了四个参数,暂时未知参数作用
其次,该函数 也返回了一个函数 createElement$1() 。
如果我们在 vue.js 文件中搜这个函数名称,我们最终会找到另外一个函数 createElement()
然后这个函数的用法 和 作用 ,官方文档上做了详细介绍 createElement 方法的使用
我们按照官网上的说明来使用一次。这两种情况都是可以正常渲染的。
new Vue({
el: "#app",
render(createElement) {
/* return createElement(
"div",
"直接使用字符串生成虚拟文本节点,而不是使用createElement创建的子级虚拟节点"
); */
return createElement("div", [createElement("h1", "使用createElement 生成的子级虚拟节点")]);
},
components: {
App,
},
});
render 函数 简写完了之后如下。
render:createElement => createElement("div", '内容'),
和 脚手架 生成的 render 函数区别就在于,我们自己写的 render 函数内部 传了两个参数, 脚手架 的render 函数只传了一个。这是因为,第一个参数的类型可以是如下类型
文档上说的是,可以是 HTML 标签名称,可以是 组件,那也就是说,我的 App 组件,直接放进去当做参数,有问题没,那必须是没问题的啊。但是,需要注意,App 不能写成字符串,因为 HTML 标签名称里面也没有这玩意啊,写成变量就自动往上找到 App 组件了。
但是对于我们开发来讲的话,我觉得完整版的其实也买啥毛病啊,为啥 官方脚手架 要给我自动引入一个 不带模板解析器的 运行时 的 Vue.js 呢?
其实只有一个原因:因为完整版的 Vue.js 文件比 运行时的 Vue.js 文件要大了将近 1/3
我们需要知道,我们写在代码里面的 .vue 文件,浏览器是不认识的,浏览器只认识 js、HTML、css 文件。我们写的 .vue 文件最终是通过 webpak 打包之后,编译成了 js、HTML、css 文件 ,浏览器解析之后,展现出页面。如果我们引入了完整版的 vue.js ,那么在我们webpack 打包编译的时候,生成的包就会变大,就会增加浏览器的加载时间。
那这个时候,可能又存在疑问了,既然没有 模板编译器 ,那我 .vue 文件中的 templete 标签,怎么解析编译的呢?这是因为 脚手架单独给 .vue 文件中的 templete 标签引入了一个编译器