1. 程式人生 > 實用技巧 >設計公共元件需要注意什麼

設計公共元件需要注意什麼

本文源於我們近期抽取的 ListFrame[參考中有介紹] 公共元件,以及後續使用和維護這個公共元件的思考 。
抽取一個公共元件,至少應當仔細考慮一下4點:

1、公共元件不應該整合定製性強的功能,可以整合通用或較固定的功能,但應預設關閉那些不常用的功能

到目前使用了 ListFrame 的列表有9個(列表共19個,3個未完成,7個尚未使用公共元件)。
這些列表的搜尋條件總共約有12種,但是listFrame只封裝了6個,且這6個 只有一個預設是開啟的。

為什麼不封裝另外6個?其的5個只有少數列表用到,封裝他們 增加了公共元件的程式碼量,但又沒有很高的利用率。
還有一個也就是類別搜尋,幾乎所有的列表都有這個搜尋條件,但不同種類的內容類別完全不同——這是定製性很強的功能(文章型別的類別,遊戲型別的類別 完全不同)!

定製性很強的功能封裝起來需要包含各種情況,邏輯較複雜,另外也使列表的邏輯分散,不利於維護。試想一下,下次再擴充套件一個型別,豈不是還要修改這個ListFrame !
(公共元件不能保持穩定的,就是失敗的)

這有點小兒科了吧!
實際上識別出哪些功能是通用的(應該封裝的),哪些是常用的(應該預設開啟的),並不是拍腦袋決定的,是在使用公共元件的過程中,不斷修正總結得出的。
維護公共元件,你一定要有一顆開放的心態。元件好不好,由使用的情況說了算,敢於承認失敗,才能不斷改進。

2、引數的配置要簡單且靈活

如果你想讓你的元件功能強大,通過一些配置就能快速擴充套件,那麼一定要避免將配置設計的過於複雜。
配置很複雜的話,別人為什麼要用?這無異於將寫原始碼的工作量 轉移到了寫配置上,沒有任何好處,反而讓程式碼更難理解(額外的要先理解你的公共元件)。

將配置設計的簡單關鍵就是:用好預設值和型別過載

構建列表框架,你必須要考慮分頁:
有些列表(如展示全部內容的列表)是沒有分頁
分頁有pageNo和pageSize屬性,且初始值是可以設定的,ajax請求時攜帶的引數名最好也是可以配置的
於是可能你的元件應該這樣使用:

  <list-frame :showPager="{
show:true, pageNo:{ name:'pageNo', initial:1 }, pageSize:{ name:'pageSize', initial:10 }}"
></list-frame>

後臺在設計介面時,通常引數名就是 pageNo 和 pageSize;前端使用場景中基本上初始的pageNo是1,pageSize為10。採用預設值,所有的配置都可以省略:

<list-frame :showPager="{show:true}"></list-frame>
<!-- 沒有傳入的欄位,就使用預設值,而非空(做好空值適配很重要) -->

為了更簡單,再加上型別過載。完整設計程式碼如下:

class PagerConfig{
    show?:boolean,
    pageNo?:{
        name?:string,
        initial?:string
    }
    pageSize?:{
        name?:string,
        initial?:string
    }
}

// 型別過載
    showPager:Boolean | PagerConfig

// 預設值的定義與使用:
const defaultPager = {
  show: true,
  pageNo: {
    name: 'pageNo',
    initial: 1
  },
  pageSize: {
    name: 'pageSize',
    initial: 10
  }
};

this.pagerConfig = Object.assign(
  {},
  defaultPager,
  typeof this.showPager === 'boolean' ? { show: this.showPager } : this.showPager
);
// this.pagerConfig 就是最終的配置了!

那麼使用時,就可以這樣寫了

<list-frame :showPager="true"></list-frame>
或:
<list-frame show-pager ></list-frame>

現在可以看到,一切變的非常簡單,同時又保持了足夠的靈活性!

3、相關的配置要集中

將相關的配置集中在一起,更利於使用者使用,可讀性更強。

ListFrame 封裝了 批量刪除 和 批量上下架 的功能。為什麼要將這兩個功能封裝呢?因為:
1、有很多業務無關邏輯值得我們去封裝,如disable校驗,刪除和下架時要彈出輸入框,要求使用者輸入刪除原因或下架原因;
2、通用性很強,幾乎所有的列表都有刪除功能,所有已釋出列表都有上下架功能;
3、不同列表除了對應的上下架介面,刪除介面不同外,好像沒有什麼其他不同的。

看看下方程式碼:
如果開啟批量刪除 除了設定 itemsDelAble 為 true,還要提供 delFn 刪除方法;如果開啟批量上下架 除了設定shelfOperateAble 為 true ,還需要提供offshelfFn 和 onshelfFn 兩個方法。
既然提開啟功能和供方法必須同時存在,為什麼不把他們繫結在一起呢?我們將 itemsDelAble 和 shelfOperateAble 有bool型別變成了 object 型別,於是很容易實現了集中配置的目標。

對比一下將配置集中前後的程式碼,是否後者更容易理解,更方便使用了呢?

    <!-- 集中配置前: -->
    <list-frame
      :getPageFn="getPage"
      :itemsDelAble="true"
      :delFn="delFn"
      :shelfOperateAble="true"
      :offshelfFn="offshelfFn"
      :onshelfFn="onshelfFn"
    ></list-frame>

    <!-- 集中配置後: -->
    <list-frame
      :getPageFn="getPage"
      :itemsDelAble="{delFn}"
      :shelfOperateAble="{offshelfFn,onshelfFn}"
    ></list-frame>

4、避免出現職能交叉的配置

我發現,這一點錯誤,即便是大型UI框架也會犯。我現在開發的專案所採用的UI框架,關於Button就存在這個問題。下面就用個api截圖來說明:(就不發 連結,也不指明是哪個框架了)

按鈕的 type 大部分值都是表示主題顏色的,如default,primary,info等,但 text(文字按鈕) 和 dashed(虛線框按鈕)除外,我覺得這兩個應該是屬於shape(形狀)的值。
這樣的 type 和 shape 職能交叉了。現在要實現一個文字按鈕,有不同顏色 —— 竟然做不到了!

我們在開發 ListFrame 也存在這樣的錯誤,後面使用時發現後才改正的,這裡就不說了,因為上面舉的例子已經能很好的說明這個注意點了。