首先是 vue 在 runtime-compiler 模式下进行执行的过程![在这里插入图片描述](https://img-blog.csdnimg.cn/de325a04634a4983984e5128ba47ad36.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NzcwMjUz,size_16,color_FFFFFF,t_70)
通过 runtime-compiler 创建的项目,会经过上述图片中的 vue 程序运行过程,但是用 runtime-only 创建的项目,会直接从 render 函数 将 挂载的 App 变成 virtual dom(虚拟dom),性能更加高效!而且 vue 的代码量更少!因此 runtime-only 小的 6KB 就是少了执行前两个步骤的代码。
让我们看下一下这两种不同的方法创建的 vue 项目中 main.js 文件的区别吧:
1、runtime-compiler 的 main.js 将 App 在 components 里面进行了注册,然后在 template 里面进行使用
2、runtimer-only 的 main.js:没有进行注册 App ,而是进行了一个 render(渲染)函数
下面我补充一下虚拟 DOM 相关的知识吧:
1、什么是虚拟 DOM?
- 虚拟 DOM本质上就是一个普通的 JS 对象,用于描述视图的界面结构
- 在 vue 中,每个组件都有一个 rende r函数,每个 render 函数都会返回一个虚拟 DOM 树,这也就意味着每个组件都对应一棵虚拟 DOM 树
2、为什么需要虚拟 DOM?
- 在 vue 中,渲染视图会调用 render 函数,这种渲染不仅发生在组件创建时,同时发生在视图依赖的数据更新时。如果在渲染时,直接使用真实 DOM,由于真实 DOM 的创建、更新、插入等操作会带来大量的性能损耗,从而就会极大的降低渲染效率。
- 因此,vue 在渲染时,使用虚拟 DOM来替代真实 DOM,主要为解决渲染效率的问题。
3、虚拟 DOM 是如何转换为真实 DOM 的?
- 在一个组件实例首次被渲染时,它先生成虚拟 DOM 树,然后根据虚拟 DOM 树创建真实 DOM,并把真实 DOM 挂载到页面中合适的位置,此时,每个虚拟 DOM 便会对应一个真实的 DOM。
- 如果一个组件受响应式数据变化的影响,需要重新渲染时,它仍然会重新调用 render 函数,创建出一个新的虚拟 DOM 树,用新树和旧树对比,通过对比,vue 会找到最小更新量,然后更新必要的真实 DOM 节点
- 这样一来,就保证了对真实 DOM 达到最小的改动。
4、模板和虚拟 DOM 的关系?
- vue 框架中有一个 compile 模块,它主要负责将模板转换为 render 函数,而 render 函数调用后将得到虚拟 DOM。
- 编译的过程分两步:
1、将模板字符串转换成为 AST(抽象语法树)
2、将 AST 转换为 render 函数 - 如果使用传统的引入方式,则编译时间发生在组件第一次加载时,这称之为运行时编译。
- 如果是在 vue-cli 的默认配置下,编译发生在打包时,这称之为模板预编译。
- 编译是一个极其耗费性能的操作,预编译可以有效的提高运行时的性能,而且,由于运行的时候已不需要编译,vue-cli 在打包时会排除掉 vue 中的 compile 模块,以减少打包体积
- 模板的存在,仅仅是为了让开发人员更加方便的书写界面代码
- vue 最终运行的时候,最终需要的是 rende r函数,而不是模板,因此,模板中的各种语法,在虚拟 DOM 中都是不存在的,它们都会变成虚拟 DOM 的配置
最后我对 render 函数做一点补充:
render: function(createElement)
在 render 方法中有一个 createElement 属性,就是上面中 render 里面的 h,它来自单词 hyperscript
这下面的两种写法是在 runtime-compiler 项目里面改写的,意味着其也可以用 render 函数来进行页面的渲染
1、普通写法:如下图解释,页面就会渲染出一个类名为 box 的 h2 标签,内容是 Hello Vue,之前的 #app 的标签就会被替换掉
还可以在数组里面添加第二个参数,也可以是 createElement 函数
2、传入组件写法:还可以现在 vue 实例外部创建一个组件,然后通过 createElement 函数进行引用
同理,上面的导入的 App 也是一个组件,所以 render的运行原理就是通过引用组件进行页面的渲染
下面的使用 runtime-only 进行的代码编写,来解释 App 组件在被调用进 main.js 的时候已经被编译成了 render 函数,就没有 template 了
这里我们打印一下 App 组件,表明:当导入(import)App 组件的时候,已经没有 template 了