Skip to content

渲染原理

渲染机制

虚拟 DOM

虚拟 DOM 是一种虚拟的,保存在内存中的数据结构,用来代表 UI 的表现,和 真实 DOM 节点保持同步。

Virtual DOM 是由一系列的 VNode 组成的。

js
const vnode = {
  type: 'div',
  props: {
    id: 'hello',
  },
  children: [
    /* 更多 vnode */
  ],
}

渲染管线

  1. 编译(Compile):Vue 模板被编译为渲染函数:即用来返回虚拟 DOM 树的函数。这一步骤可以通过构建步骤提前完成,也可以通过使用运行时编译器即时完成。
  2. 挂载(Mount):运行时渲染器调用渲染函数,遍历返回的虚拟 DOM 树,并基于它创建实际的 DOM 节点。这一步会作为响应式副作用执行,因此它会追踪其中所用到的所有响应式依赖。
  3. 更新(Patch):当一个依赖发生变化后,副作用会重新运行,这时候会创建一个更新后的虚拟 DOM 树。运行时渲染器遍历这棵新树,将它与旧树进行比较,然后将必要的更新应用到真实 DOM 上去。

Render Pipeline

渲染函数

h()

Vue 提供了一个 h() 函数用于创建 VNodes:

js
import { h } from 'vue'

const vnode = h(
  'div', // type
  { id: 'foo', class: 'bar' }, // props
  [
    /* children */
  ],
)

通过 isVNode() 判断是否为 VNode

ts
function isVNode(value: unknown): boolean

JSX / TSX

JSX 是 JavaScript 的一个类似 XML 的扩展,与 React 类似,例如:

jsx
const vnode = <div id={dynamicId}>hello, {userName}</div>

在 JSX 表达式中,使用大括号来嵌入动态值:

jsx
const vnode = <div id={dynamicId}>hello, {userName}</div>

注意:Vue 的 JSX 转换方式与 React 中 JSX 的转换方式不同

  • 可以使用 HTML attributes 比如 classfor 作为 props - 不需要使用 classNamehtmlFor
  • 传递子元素给组件 (比如 slots) 的方式不同。

函数式组件

函数式组件是一种定义自身没有任何状态的组件的方式。它们很像纯函数:接收 props,返回 vnodes。函数式组件在渲染过程中不会创建组件实例 (也就是说,没有 this),也不会触发常规的组件生命周期钩子。

示例:

js
function MyComponent(props, context) {
  // ...
}

参数说明:

  • props:因为函数式组件里没有 this 引用,Vue 会把 props 当作第一个参数传入;

  • context:它包含三个属性:attrsemitslots

    它们分别相当于组件实例的 $attrs$emit$slots 这几个属性。

大多数常规组件的配置选项在函数式组件中都不可用,除了 propsemits。我们可以给函数式组件添加对应的属性来声明它们:

js
MyComponent.props = ['value']
MyComponent.emits = ['click']

如果这个 props 选项没有被定义,那么被传入函数的 props 对象就会像 attrs 一样会包含所有 attribute。除非指定了 props 选项,否则每个 prop 的名字将不会基于驼峰命名法被一般化处理。

对于有明确 props 的函数式组件,attribute 透传的原理与普通组件基本相同。然而,对于没有明确指定 props 的函数式组件,只有 class、style 和 onXxx 事件监听器将默认从 attrs 中继承。在这两种情况下,可以将 inheritAttrs 设置为 false 来禁用属性继承:

js
MyComponent.inheritAttrs = false

函数式组件可以像普通组件一样被注册和使用。如果你将一个函数作为第一个参数传入 h,它将会被当作一个函数式组件来对待。

基于 MIT 许可发布