Skip to content

使用位元表示 VNode

使用位元表示 VNode 的型別

VNode 有各種型別。例如,目前實作的包括:

  • 元件節點
  • 元素節點
  • 文位元組點
  • 子元素是否為文字
  • 子元素是否為陣列

在未來,將實作更多型別的 VNode。例如,slot,keep-alive,suspense,teleport 等。

目前,分支是使用 type === Texttypeof type === "string"typeof type === "object" 等條件進行的。

逐一檢查這些條件是低效的,所以讓我們嘗試按照原始實作使用位元來表示它們。在 Vue 中,這些位元被稱為"ShapeFlags"。顧名思義,它們表示 VNode 的形狀。(嚴格來說,在 Vue 中,ShapeFlags 和 Text,Fragment 等符號用於確定 VNode 的型別。) https://github.com/vuejs/core/blob/main/packages/shared/src/shapeFlags.ts

位元標誌是指將數字的每一位元視為特定標誌。

讓我們以下面的 VNode 為例:

ts
const vnode = {
  type: 'div',
  children: [
    { type: 'p', children: ['hello'] },
    { type: 'p', children: ['hello'] },
  ],
}

ShapeFlags pack VNode shape into bits

首先,標誌的初始值是 0。(為了簡單起見,這個解釋使用 8 位元。)

ts
let shape = 0b0000_0000

現在,這個 VNode 是一個元素並且有一個子元素陣列,所以設定 ELEMENT 標誌和 ARRAY_CHILDREN 標誌。

ts
shape = shape | ShapeFlags.ELEMENT | ELEMENT.ARRAY_CHILDREN // 0x00010001

透過這種方式,我們可以使用一個名為"shape"的數字來表示這個 VNode 是一個元素並且有一個子元素陣列的資訊。我們可以透過在渲染器或程式碼的其他部分的分支中使用它來高效地管理 VNode 的型別。

ts
if (vnode.shape & ShapeFlags.ELEMENT) {
  // vnode 是元素時的處理
}

由於這次我們沒有實作所有的 ShapeFlags,請嘗試實作以下內容作為練習:

ts
export const enum ShapeFlags {
  ELEMENT = 1,
  COMPONENT = 1 << 2,
  TEXT_CHILDREN = 1 << 3,
  ARRAY_CHILDREN = 1 << 4,
}

你需要做的是:

  • 在 shared/shapeFlags.ts 中定義標誌
  • 在 runtime-core/vnode.ts 中定義 shape
    ts
    export interface VNode<HostNode = any> {
      shapeFlag: number
    }
    加入這個並在 createVNode 等函式中計算標誌。
  • 在渲染器中基於 shape 實作分支邏輯。

這就是本章的解釋。讓我們開始實作吧!

基於 MIT 許可證發布。