元件透過 <Canvas />
渲染在畫布上,內容完全由元件樹 componentTree
驅動,但也有一些情況我們需要把某個元件例項渲染到元件樹之外,比如全屏、置頂等場景,甚至有些時候我們要渲染一個不在元件樹中的臨時元件,卻要擁有一系列畫布能力。
為了讓元件渲染更靈活,我們暴露出 <ComponentLoader>
API:
import { createDesigner } from 'designer'
const { Designer, Canvas, ComponentLoader } = createDesigner()
const App = () => {
return (
<Designer componentTree={/** ... */}>
<Canvas />
{/** 任意位置,甚至 Canvas 的元件例項內使用 ComponentLoader 載入任意元件 */}
<ComponentLoader />
</Designer>
)
}
元件載入器有三種用法:按元件 ID 載入、按元件樹路徑載入、動態元件,下面分別介紹。
按元件 ID 載入
將元件樹上的某個元件渲染到任何地方,即一個元件例項渲染到 N 個地方,例項級別資訊共享,渲染為 N 份:
<ComponentLoader componentId="input1" />
如上例子,將元件 ID 為 input1
的元件渲染到目標位置。
甚至可以在元件內套元件,比如我們定義一個容器元件,內建渲染 ID 為 input1
的子元件:
const container: ComponentMeta = {
componentName: 'container',
// 元件 props 會自動注入 ComponentLoader
element: ({ ComponentLoader, children }) => {
return (
<div>
<ComponentLoader componentId="input1" />
{children}
</div>
)
}
}
當該元件 ID 在元件樹中被移除時,<ComponentLoader componentId="input1" />
返回 null
。
按元件樹路徑載入
如果元件在元件樹上沒有 ID,或者你希望固定渲染某個位置的元件,而無論元件樹如何變化,那麼就可以採用按元件樹路徑的載入模式,將 componentId
替換為 treePath
即可:
<ComponentLoader treePath="children.0" />
如上例子,渲染的是 componentTree
根節點 children.0
位置的子元件,同樣,但元件不存在時返回 null
。
動態元件
如果要渲染一個不存在於元件樹的元件例項,還可以這麼用 <ComponentLoader />
:
<ComponentLoader standalone componentName="card" />
即新增 standalone
表示它為一個 “孤立” 元件,即不存在於元件樹的元件,以及 componentName
指定元件名。
之所以不需要指定 componentId
,是因為每個 ComponentLoader
此時都是一個唯一的例項,在 designer
內部會自動分配一個固定的元件 ID。
這麼設計非常靈活,但實現起來難度是有一些,主要注意兩點:
- 動態元件不存在於元件樹,但我們之前設計在元件元資訊的所有功能都要可以響應,這就要求框架程式碼不能依賴元件樹產生作用,而是將所有元件獨立儲存計算,包括元件樹上的,以及動態元件。
- 效能,獨立元件載入器之間的執行並無關聯,因為框架本身為響應式,為了防止頻繁重新整理或頻繁計算需要設計一套自動批處理機制,類似 React 自動 batch 的實現。
對於動態元件,我們還可以傳遞更多引數:
<ComponentLoader standalone componentName="chart" props={{ color: 'red' }}>
<button>click</button>
</ComponentLoader>
如上例子,我們傳了額外 props
屬性,以及一個子元素給 chart
元件例項。
特別的,如果傳遞了 componentId
,可以將該動態元件的 ID 固定下來,方便進行聯動:
<ComponentLoader standalone componentName="chart" componentId="abc" />
但動態元件也有一些限制,如下:
- 該方式渲染的元件元資訊定義的
defaultProps
、props
不會生效,因為不存在於元件樹中。 - 該元件無法透過
deleteComponent
刪除,也無法透過setProps
、setComponent
等修改,因為渲染完全由父元件控制,而不由元件樹控制。 - 不能用
setParent
改變這種元件的位置,因為其位置在程式碼中被固定了。
總結
其實 <Canvas />
根節點本質上等價於 <ComponentLoader treePath="" />
,即從根節點開始渲染一個元件例項。
所以提供 ComponentLoader
勢必會讓業務能力更靈活,在任意位置渲染元件,甚至渲染一個不存在於元件樹的動態元件。
討論地址是:精讀《ComponentLoader 與動態元件》· Issue #482 · dt-fe/weekly
如果你想參與討論,請 點選這裡,每週都有新的主題,週末或週一釋出。前端精讀 - 幫你篩選靠譜的內容。
關注 前端精讀微信公眾號
<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">
版權宣告:自由轉載-非商用-非衍生-保持署名(創意共享 3.0 許可證)