關於元件庫設計的文章一搜能出來一大把,但大多數都是從UI角度或者視覺規範層面來講的,但隨著前端技術的發展和迭代,前端這個崗位早已不是過去定義的實現樣式那麼簡單了,這篇文章會站在一個技術同學的角度來聊一下元件庫的設計除了樣式還有哪些可以關注的。
元件庫應用場景思考
元件的本質其實在於程式碼的複用和抽象,以此起到提升開發效率的目的, 可以說一個元件的靈魂就在於對業務場景的解構,比如各種控制元件的抽象,事件的抽象,樣式的抽象等,並通過組合和配置的方式實現業務需求,某種程度上一個元件庫就像是一個工具箱,為業務場景的開發提供各種零件,而要如何設計這些零件,就需要對應用場景有一個深入的瞭解和思考。
比如C端的元件庫,需要在UI,效能,瀏覽器相容性上有更多的思考,追求更極致的互動體驗和視覺體驗,同時C端應用的UI經常會根據節日,活動的主題而切換, 在元件庫的設計上也要考慮到個性化的擴充套件空間。
而B端的元件庫,則更加註重易用性和可複用性,保證中臺或者B端工具類應用的高速迭代和高效使用。同時B端應用會涉及很多的資料展示,和增刪改查操作,這就需要元件庫在互動控制元件上有更細的職責劃分和更豐富的選擇。
除了應用的業務場景不同,還可能存在平臺場景的多元化問題,比如同一套元件庫是否能在H5和小程式中複用。這些都需要元件庫設計者在規劃之初就考慮進去。
目前主流的元件庫分析
目前主流的元件庫可以分為兩大類:
一類是基於幾大前端框架的生態來實現的,在設計上都已經形成了自己的風格和規範,也有自己的沉澱,比如基於Vue生態的element, 基於react的antD 等。他們的優點是已經發展的很成熟了基本上可以cover大多數的業務場景,缺點是元件庫在跨框架遷移上的成本較大。
還有一類是元件庫則是針對跨端的需求設計的。通常底層會依賴一套跨平臺開發的框架 如京東的taro,美團的mpVue, 淘寶的Rax等,他們的核心思想也是 write one run anywhere, 這類元件庫在實現上, 主要利用框架提供的基礎實現儘可能抹平各個平臺的差異,讓使用者可以基於一套開發規範,實現多個平臺的業務。這類元件的優點是,可以減少開發者在跨平臺上的學習成本,缺點是元件庫的豐富度還有所欠缺,能覆蓋的場景也比較侷限
除了上述的兩大類,騰訊的omi,則是利用web comp的特性,來實現的跨端和跨框架,可以算是下一代前端框架的一個嘗試了。
元件庫的規劃
元件庫的設計過程其實也很類似一款產品的設計過程,會有前期的場景調研,競品分析, 需求整理,使用者體驗(這裡應該叫開發體驗),以及持續的試錯迭代。
綜合上面的一些思考和分析,我會試著把元件庫規劃如下:
元件需求:
-
元件膠水層 --> 實現元件和實際的業務之間的銜接
-
元件代理層 --> 可以基於代理實現元件內部的靈活呼叫和區域性重新整理
-
元件互動層 --> 根據業務場景 抽象基於互動事件的功能,並通過裝飾器注入
-
元件擴充套件層 --> 實現元件間的克隆,繼承,擴充套件
-
元件庫cli --> 方便元件的迭代和工程化
-
效能 --> 實現最小粒度的重新渲染
元件庫解決痛點
- function component 外部不方便繼承擴充套件
- 實現元件和呼叫方互動時的區域性更新,提高效能
- 通過膠水層和前端框架連線,降低框架遷移的成本
- 封裝事件驅動的狀態管理,也可以配合一個狀態元件做擴充套件
元件內部系統:
-
樣式
-
事件
-
狀態
-
繼承
元件庫架構選型(暫定,後期可能還會調整)
以rax為基礎,結合mono repo, peer dep 和 元件的多型協議 開發, 實現按需引入,保證業務呼叫層在跨端場景下的介面統一,最大發揮各個端的特性。
元件庫features(暫定,後期可能還會調整):
- 區域性重新整理 和 跨層級呼叫
Modal.proxy.visible = true;
Modal.show(config)
複製程式碼
-
擴充套件繼承
//克隆 const Modal2 = Modal.clone(); 複製程式碼
//擴充套件 const Modal2 = genModal({ methods: { cancel() { console.log('%c rewrite the cancel','color:#299865',this); this.visible = false; } } }); 複製程式碼
//批量擴充套件 import {factoryAuto} from 'component' const {Button, Modal} = factoryAuto(pubConfig); 複製程式碼
//繼承 const Button2 = genButton(Button1.proxy, newFeature) 複製程式碼
-
輕量的狀態元件
<Button
x-for={(item, key) in statusList}
type="+success"
onClick={_ => trySingle(item)} >
wait{key}
</Button>
複製程式碼
function trySingle (item) {
performance.watch()
item.choosed = !item.choosed
if (item.choosed) {
return new Status('pending...', { backgroundColor: 'green' })
} else {
return new Status(null)
}
}
複製程式碼
- 裝飾器注入
@addTransition('visible')
class BaseMix extends Base {}
複製程式碼
- scope作用域元件(區域性render)
<Button scope={item}
x-for={(item, key) in scopeList}
type="+success"
onClick={_ => {tryScope(item)}} >
wait{key}
</Button>
複製程式碼
function tryScope(item) {
performance.watch();
item.choosed = !item.choosed;
}
複製程式碼
- 事件裝飾器(loading, lock等)
@addLoading
class EventCtxMix extends EventCtxBase {}
複製程式碼
function Okfunc() {
return new Promise((resolve, reject) => {
//封裝了防重鎖和loading效果
setTimeout(() => {
resolve()
}, 1600)
})
}
複製程式碼
元件庫未來展望
前端技術的一個特點就是變化快,除了各大框架提供的元件能力, 這幾年web components 的概念也逐漸成為熱點。除此之外隨著react hooks的橫空出世 function components時代也隨之而來,相比於class compontents 基於hooks的function compontents在設計上更加靈活但外部擴充套件性也相對較差,基於這層考慮我有一個常識性的構想是在框架上層封裝元件的邏輯層和樣式層的介面,通過膠水層和元件連線只借助元件完成檢視層的渲染,從而打破元件庫和框架的次元壁,元件庫的核心部分可以遷移到其他框架甚至web compontents,只需要重新coding膠水層就行了。當然這個構想距離最終落地還需要大量的實踐基礎。