前言:
本文是我看的Vue.js设计与实现这本书第一篇 框架设计概览 的第3章 Vue.js 3 的设计与思路的一些总结与收获。
第一篇 框架设计概览 有三个章节:权衡的艺术、框架设计的核心要素、Vue.js 3 的设计思路。在第1章中,讲的是框架设计是权衡的艺术,里面存在着取舍,例如性能与可维护性之间的取舍、运行时与编译时之间的取舍等。在第2章中,讲的是框架设计的几个核心要素;第3章中,主要是Vue.js 3 的设计思路、工作机制和重要的组成部分,还有各个模块之间是如何协作之类的。
第3章 Vue.js 3 的设计与实现
3.1 声明式地描述UI
我们已经知道Vue.js3是一个声明式的UI框架,如果让我们设计一个声明式的UI框架,我们怎么设计呢?像DOM元素,属性,事件,元素的层级结构等;怎么声明式描述?
Vue.js 3相应解决:DOM元素和属性的话跟HTML标签一致;动态绑定属性的话则是使用:或v-bind来描述;事件用@或v-on来描述事件;层级结构也适合HTML标签一致。
之后除了上面声明式描述UI,还可以用Javascript对象来描述。使用Javascript对象描述UI更加灵活。而使用Javascript对象描述UI的方式,其实就是所谓的虚拟DOM。
其实在Vue.js组件中手写的渲染函数就是使用虚拟DOM来描述UI的,如:
import {h} from 'vue'
export default {
render() {
return h('h1',{ onClick: handler }) //虚拟DOM
}
}
Vue.js会根据组件的render函数的返回值拿到虚拟DOM,然后就可以把组件的内容渲染出来了。
3.2 初始渲染器
我们已经了解到虚拟DOM就是用Javascript对象来描述真实的DOM结构。
而虚拟DOM怎么变成真实DOM渲染到浏览器的:渲染器。
渲染器的作用就是把虚拟DOM渲染为真实DOM,渲染器renderer的实现思路分三步:创建元素、为元素添加属性和事件、处理children。渲染器的实现原理其实很简单,都是使用一些我们使用一些我们熟悉的DOM操作API来完成渲染工作。它的精髓主要在更新节点的阶段。
3.3 组件的本质
我们知道了虚拟DOM是描述真实DOM的普通Javascript对象,渲染器会把这个对象渲染为真实DOM元素。那么组件又是什么呢?组件和虚拟DOM有什么关系?渲染器如何渲染组件?
其实虚拟DOM除了能够描述真实DOM,还能描述组件。组件并不是真实DOM元素,一句话总结:组件就是一组DOM元素的封装,这组DOM元素就是组件要渲染的内容,因为我们可以定义一个函数来代表组件,而函数的返回值就代表组件要渲染的内容。
可知,组件的返回值也是虚拟DOM,它代表组件要渲染的内容。
3.4 模板的工作原理
无论是手写虚拟DOM还是使用模板,都属于声明式地描述UI,我们知道虚拟DOM是通过渲染器渲染成真实DOM的。那模板如何工作的?
这就要提到Vue.js框架中的另一个重要组成部分:编译器。
编译器的作用其实就是将模板编译为渲染函数。
对于<template>标签,里面的内容就是模板内容,编译器会把模板内容编译成渲染函数并添加到<script>标签块的组件对象上。
所以,无论使用模板还是渲染函数,对于一个组件来说,它要渲染的内容最终是通过渲染函数产生的,然后渲染器再把渲染函数返回的虚拟DOM渲染成真实DOM,这就是模板的工作原理。也是Vue.js渲染页面的流程。
3.5 Vue.js是各个模块组成的有机整体
组件的实现依赖于渲染器,模板的编译依赖于编译器,并且编译后生成的代码是根据渲染器和虚拟DOM的设计决定的,因此Vue.js的各个模块之间是互相关联、互相制约的,共同构成一个有机整体。
我们知道渲染器和编译器之间是存在信息交流的,它们互相配合使得性能进一步提升,而它们之间交流的媒介就是虚拟DOM对象。
3.6 总结
Vue.js是一个声明式的框架,Vue.js采用模板的方式来描述UI,它同样支持使用虚拟DOM来描述UI。
然后是渲染器,渲染器的作用是把虚拟DOM对象渲染为真实DOM元素。它的工作原理是,递归地遍历虚拟DOM对象,并调用原生DOM API来完成真实DOM的构建。渲染器的精髓在于后续的更新,它会通过Diff算法来找出变更的内容,并只更新需要更新的内容。
之后是组件的本质。组件其实就是一组虚拟DOM元素的封装,它可以是一个返回虚拟DOM的函数,也可以是一个对象,但这个对象下必须要有一个函数用来产出组件要渲染的虚拟DOM。
Vue.js的模板会被一个叫做编译器的程序编译为渲染函数。
最后,编译器、渲染器都是Vue.js的核心组成部分,它们之间是存在信息交流的,它们之间交流的媒介就是虚拟DOM对象。它们共同构成一个有机的整体,不同模块之间互相配合,提升框架性能。