Vue.js 设计与实现解析 
书籍推荐
《Vue.js 设计与实现》这本书是 Vue 核心开发团队成员霍春阳编写的,没有源码阅读,直接分析了 Vue 3 的一些设计哲学。
《Vue.js 技术内幕》则是源码阅读,从 Vue 的源码来分析 Vue 的一些核心实现。
1. 框架设计概述 
1.1 权衡的艺术 
框架的设计本身就是一种权衡的艺术。——尤雨溪
1.1.1 命令式和声明式 
命令式编程和声明式编程是两种不同的编程范式,Vue 给用户体验是声明式的,但是内部实现是命令式的。
命令式编程主要关注过程:
const div = document.querySelector('#app')
div.innerHTML = 'Hello World'
div.addEventListener('click', () => {
  alert('Hello World')
})声明式编程主要关注结果:
<template>
  <div @click="alert('Hello World')">
    Hello World
  </div>
</template>1.1.2 性能与可维护性 
命令式编程的性能更好,直接使用原生的 JavaScript 实现。而声名式编程的无论界面如何,其内部一定会实现命令式的逻辑代码,所以性能上会有一定的损耗。
命令式编程的可维护性远远大于命令式代码,因为其代码更加直观,更容易理解。
DOM 渲染方式的直观比较:
| 项目 | innerHTML(字符串模板) | 虚拟 DOM | 原生 JavaScript | 
|---|---|---|---|
| 心智负担 | 中等 | 小 | 大 | 
| 性能 | 低 | 可接受,不错 | 高 | 
| 可维护性 | 中等 | 强 | 高 | 
1.1.3 运行时和编译时 
运行时渲染指的是利用 render 函数将虚拟 DOM 渲染成真实 DOM 的过程。这个过程没有编译的内容,无法分析用户提供的内容。
编译时渲染指的是将模板编译成 DOM 元素。这个过程会分析用户提供的内容,理论上性能更好。例如 Svelte 就是编译时渲染,但是作者也在书中强调了 Svelte 的性能没有达到预期的效果。
还有一种方式,即运行时 + 编译时,这个过程可分为两个阶段:
- 将模板编译成 render函数
- 利用 render函数将虚拟 DOM 渲染成真实 DOM
这也是 Vue 的主要实现方式。
1.2 框架设计的核心要素 
1.2.1 控制代码体积 
使用环境变量(如 __DEV__)和 摇树优化(Tree Shaking)来控制代码体积。
1.2.2 输出不同的构建产物 
通过构建不同的打包产物来应对不同的使用场景(如 CommonJS、ES Module、UMD、Runtime 等)。
1.2.3 错误提示与处理 
Vue 内部提供了一个同意的错误处理接口 callWithErrorHandling,用于处理错误。
1.2.4 提升用户开发体验 
内部使用 TypeScript 进行开发,提供了类型提示。包含了大量类型校验,可以保证项目的可维护性,提升用户开发体验,降低用户心智负担。
1.3 Vue.js 3 的设计思路 
1.3.1 描述 UI 的形式 
声名式的模板描述:
<template>
  <div :id="tid" :class="{ active: isActive }" @click="handleClick">
    {{ text }}
  </div>
</template>命令式的 render 函数:
import { h } from 'vue'
export default {
  render() {
    return h('div', {
      id: this.tid,
      class: {
        active: this.isActive
      },
      onClick: this.handleClick
    }, this.text)
  }
}1.3.2 初始化渲染器 
渲染器是 createRenderer 函数的返回值,它是一个对象,包含了 render 方法。
渲染函数需要两个参数,第一个参数是虚拟节点 vnode,第二个参数是容器 container,是真实的 DOM 元素。渲染函数的作用是将虚拟节点渲染成真实节点,然后挂载到容器上。抽象一点来说就是把 vnode 挂载到 container 上。
1.3.3 组件的本质 
Vue 以组件作为最小颗粒,Vue 程序的本质就是大量的组件渲染。
组件就是一组 DOM 元素的封装。一个组件就是一个 JavaScript 对象(VNode),内部封装了 DOM 元素的结构、样式、事件等。
1.3.4 模板的工作原理 
这部分在上一节已经讲过了,可以阅读原著。