vue3的设计思路(4)模板的工作原理

无论是手写虚拟 DOM(渲染函数)还是使用模板,都属于声明式地描述 UI,并且 Vue.js 同时支持这两种描述 UI 的方式。

我们已经知道虚拟 DOM 是如何渲染成真实 DOM 的,那么模板是如何工作的呢?这就要提到 Vue.js 框架中的另外一个重要组成部分:编译器。

编译器和渲染器一样,只是一段程序而已,不过它们的工作内容不同。
编译器的作用其实就是将模板编译为渲染函数,例如给出如下模板:

<div @click="handler">click me</div>

以我们熟悉的 .vue 文件为例,一个 .vue 文件就是一个组件,如下所示:

<template>
  <div @click="handler">click me</div>
</template>
<script>
export default {
  data() {
    /* ... */
  },
  methods: {
    handler: () => {
      /* ... */
    },
  },
};
</script>

其中 <template> 标签里的内容就是模板内容,编译器会把模板内容编译成渲染函数并添加到 <script> 标签块的组件对象上,所以最终在浏览器里运行的代码就是:

export default {
  data() {
    /* ...
     */
  },
  methods: {
    handler: () => {
      /* ... */
    },
  },
  render() {
    return h("div", { onClick: handler }, "click me");
  },
};

所以,无论是使用模板还是直接手写渲染函数,对于一个组件来说,它要渲染的内容最终都是通过渲染函数产生的,然后渲染器再把渲染函数返回的虚拟 DOM 渲染为真实 DOM,这就是模板的工作原理,也是 Vue.js 渲染页面的流程。

Vue.js 是各个模块组成的有机整体

组件的实现依赖于渲染器,模板的编译依赖于编译器,并且编译后生成的代码是根据渲染器和虚拟 DOM 的设计决定的,因此 Vue.js 的各个模块之间是互相关联、互相制约的,共同构成一个有机整体。

我们以编译器和渲染器这两个非常关键的模块为例,看看它们是如何配合工作,并实现性能提升的。
假设我们有如下模板:

<div id="foo" :class="cls"></div>

根据上文的介绍,我们知道编译器会把这段代码编译成渲染函数:

render() {
     // 为了效果更  加直观,这里没有使用 h 函数,而是直接采用了虚拟 DOM 对象
     // 下面的代码  等价于:
     // return h('div', { id: 'foo', class: cls })
     return {
       tag: 'div',
       props:   {
           id:   'foo',
         class: cls
       }
     }
 }

在这段代码中,cls 是一个变量,它可能会发生变化。
我们知道渲染器的作用之一就是寻找并且只更新变化的内容,所以当变量 cls 的值发生变化时,渲染器会自行寻找变更点。
对于渲染器来说,这个“寻找”的过程需要花费一些力气。
那么从编译器的视角来看,它能否知道哪些内容会发生变化呢?如果编译器有能力分析动态内容,并在编译阶段把这些信息提取出来,然后直接交给渲染器,这样渲染器不就不需要花费大力气去寻找变更点了吗?这是个好想法并且能够实现。Vue.js 的模板是有特点的,拿上面的模板来说,我们一眼就能看出其中 id=“foo” 是永远不会变化的,而 :class=“cls” 是一个 v-bind 绑定,它是可能发生变化的。
所以编译器能识别出哪些是静态属性,哪些是动态属性,在生成代码的时候完全可以附带这些信息:

 render() {
  return {
    tag: "div",
    props: {
      id: "foo",
      class: cls,
    },
    patchFlags: 1, // 假设数字 1 代表 class 是动态的
  };
}

如上面的代码所示,在生成的虚拟 DOM 对象中多出了一个 patchFlags 属性,我们假设数字 1 代表“ class 是动态的”,这样渲染器看到这个标志时就知道:“哦,原来只有 class 属性会发生改变。”对于渲染器来说,就相当于省去了寻找变更点的工作量,性能自然就提升了。
通过这个例子,我们了解到编译器和渲染器之间是存在信息交流的,它们互相配合使得性能进一步提升,而它们之间交流的媒介就是虚拟 DOM 对象。当然,虚拟 DOM 对象中会包含多种数据字段,每个字段都代表一定的含义。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值