Skip to content

Vue 模板的本质

介绍

接下来的内容,可以让你对 vue 对模板彻彻底底的毕业,一旦毕业,你就再也不需要去学习它了。

定义

模板的本质就是一个语法糖。实际上在运行时它是没有的,运行的而是另外的东西。

函数渲染

在 vue3 中我们可以直接在 setup 函数中返回一个渲染函数,渲染函数的作用就是在渲染,那么什么是渲染呢?就是封装一些虚拟节点,再去递归遍历这个节点,通过创建元素形成 DOM 树。

vue3 中使用 h 函数来创建虚拟节点。

vue
<script lang="ts">
  import { h } from 'vue'

  export default {
    setup() {
      return () => {
        const list = []

        for (let i = 0; i < 100; i++) {
          list.push(h('li', null, i))
        }

        return h('ul', null, list)
      }
    }
  }
</script>

也就是在浏览器里面真正运行的就是这个渲染函数,因为它描述了这个组件的渲染过程,渲染的结果就是页面的结构。而模板就是这一切的语法糖而已。

因为我们自己手写渲染函数比较麻烦,所以就有了模板一样的语法糖,像是 html 一样,就会比较高效快捷。

像是这样:

vue
<template>
  <ul>
    <li v-for="i in 100">{{ i }}</li>
  </ul>
</template>

模板编译

既然模板只是一个语法糖,那么它肯定是有一个时间节点将语法糖转换为 render 函数,那么这个变化的过程,就是常说的模板编译,说到编译,就会有两个问题:

是什么时候做的呢?是谁来做的呢?

谁来做的呢?我门都知道,vue 中有很多模块,其中就有编译器模块,叫 compiler,在 vue 的 packages 中可以看到 compiler-corecompiler-domcompiler-sfccompiler-ssr 等编译模块。

什么时候做呢?这个时候一般分为两种情况,主要涉及到一些效率和性能问题。

第一种是运行时。也就是代码在运行到浏览器的时候再编译,叫运行编译,通常使用传统工程开发的时候,使用 script 引入 vue 包的方式,像是这样:

html
<script src="./vue.js"></script>
<script>
  new Vue({
    template: `<div>123</div>`
  })
</script>

这样的做法缺陷也非常明显,第一是编译模块要打包进去,引入要在浏览器阶段编译,第二点就是体积大。

第二种就是编译时编译,为什么推荐使用像 vite 这样的开发框架,当然原因有很多,其中比较重要的是,模板编译这一步,在编译阶段就已经完成了,我门在 *.vue 中写的内容,其实就是一段字符串,通过打包、模板编译将它变化为 render 函数,真正在浏览器中运行的就直接说 render 函数了,而不需要在浏览器阶段去编译了,所以编译模块也不需要打包,也可以大幅度提高运行效率。

结论

所以我门在模板中写的什么 v-forv-if 指令啊,最终运行的时候就都没有了。运行的就是一个循环编译、三运运算符等一些普通的 js 代码。