在第 1 章中,我们阐述了框架设计是权衡的艺术,这里面存在取舍,例如性能和可维护性之间的取舍、运行时和编译时之间的取舍。在第 2 章中,我们详细讨论了框架设计的几个核心要素,有些要素是框架设计者必须要考虑的,另一些要素则是从专业和提升开发体验的角度考虑的。框架的设计将就全局视角的把控,一个项目就算在大,也是存在一条核心思路的,并围绕核心展开。本章就从全局视角了解 Vue.js 3 的设计思路、工作机制及其重要的组成部分。可以把这些组成部分当作独立的功能模块,看看它们之间是如何相互配合的。后续的章节中,我们会深入各个功能模块了解它们的运作机制。
第一篇 框架设计概览
虚拟DOM
渲染器
组件
模板
编译器
3.1 声明式描述 UI(模板、Javascript 对象)
Vue.js 3 是一个声明式的 UI 框架,意思是用户在使用 Vue.js 3 开发页面时是声明式地描述 UI 的。
在 Vue 中,我们可以使用模板来描述 UI,模板中可以使用各种标签来描述 UI,哪怕是事件,也有与之对应的描述方式。用户不需要手写任何命令式代码,这就是所谓的声明式描述 UI。
1 | <div @click="handleClick"> |
除了使用模板来描述 UI,我们还可以用 JavaScript 对象来描述:
1 | const test = { |
使用 JavaScript 对象描述 UI 更加灵活,但是它的可读性不如模板。而用 JavaScript 对象描述 UI 的方式,就是所谓的虚拟DOM
Vue 会根据组件的 render 函数的返回值,拿到虚拟 DOM,然后根据虚拟 DOM 生成真实 DOM,最后将真实 DOM 挂载到页面中。
3.2 初识渲染器
我们已经了解了什么是虚拟DOM
(用JavaScript 对象来描述真实的 DOM 结构)。那么,虚拟DOM
是如何变成真实 DOM 渲染到浏览器页面中的呢 —— 渲染器
实现思路:
- 把 vnode.tag 作为标签名创建 DOM 元素
- 为元素添加属性和事件
- 遍历 vnode.props 对象,key 以 on 开头的是事件,否则是属性
- 处理 children
- 如果 children 是一个数组,递归调用 render 函数,将返回的 vnode 作为子节点添加到元素中
- 如果 children 是一个字符串,创建文本节点添加到元素中
3.3 组件的本质
组件是一组 DOM 元素的封装,这组 DOM 元素就是组件要渲染的内容,因此可以定义一个函数来代表组件,而函数的返回值(也是虚拟 DOM)就代表组件要渲染的内容
3.4 模板的工作原理
模板是如何工作的 —— 编译器
编译器的作用是将模板编译为渲染函数:
1 | // <div @click="handleClick">click me</div> |
无论是使用模板还是手写渲染函数,对于一个组件来说,要渲染的内容最终都是通过渲染函数产生的,然后渲染器再把渲染函数返回的虚拟 DOM 渲染为真实 DOM,这就是模板的工作原理,也是 Vue.js 渲染页面的流程。
3.5 Vue.js 是各个模板组成的有机整体
如前所述,组件的实现依赖于渲染器
,模板的编译依赖于编译器
,并且编译后生成的代码是根据渲染器和虚拟 DOM 的设计决定的,因此 Vue.js 的各个模板之间是互相关联、互相制约的,共同构成一个整体。