我是這麼設計業務[封裝組件]

前言

hello,你們好!我是linvue

今天又想和你們分享封裝組件這件事。在開發業務需求的過程當中,咱們可能會遇到一個全新的業務需求,也可能會遇到一個原來已有的功能去迭代新的功能。node

顯然,如何去設計一個全新的業務需求值是值得咱們去思考的。git

一樣,在一個原有的功能基礎上去開發迭代也是值得去思考的。github

而不只僅只是command+ccommand+v了!web

這篇文章也算是覆盤總結本身對於需求如何去設計組件。element-ui

寫文總結不易,如有更好的設計和思想,期待一塊兒碰撞。數組

需求&思考

需求的擬稿:markdown

當我拿到需求擬稿的時候,我先看了element-ui的級聯組件不能知足業務,在此基礎上改造也相對麻煩。因此最終我仍是打算本身封裝一個級聯組件。數據結構

接下來,我根據需求思考要實現的功能以下:函數

1.支持用戶經過搜索類目,進行選擇。

2.支持用戶經過展開類目點擊選擇。(ps:點擊第一個面板時將它子節點的第一級面板所有展開)

3.初始化狀態,將默認展開第一個節點的第一位的因此節點。

4.支持正選和反選節點。

5.面板的每一個搜索框可控制該面板的搜索。

如何實現需求

明確好本身要實現的需求功能以後,我所認爲的是先不要急於編寫代碼,應該再作一個深刻的分析思考。

我先從數據結構入手,這個數據結構是樹形的。相似這樣的:

const data=[
	{
    	text: "指南",
    	id: 2,
        children: [
          {
            text: "設計原則",
            id: 2.1,
            children: [
              {
                text: "導航1",
                id: 2.112,
              },
              {
                text: "導航2",
                id: 2.113,
              },
              {
                text: "導航3",
                id: 2.114,
              },
            ],
          },
          {
            text: "設計原則2",
            id: 2.2,
            children: [
              {
                text: "導航2",
                id: 2.21,
              },
            ],
          },
    ],
  },
]
複製代碼

依據這樣的樹形數據格式,我能夠明確這須要一個遞歸組件來實現。

可是如今有個關鍵的問題出現了,模板如何渲染這樣的數據格式?

  • 方案1:在設計這個遞歸組件時,是要把每個node節點當成一個遞歸組件,好比遍歷一個node節點,如有children屬性的話,那麼就一直遞歸下去,直到遇到節點沒有children屬性時中止。而後再遍歷下一個節點...

  • 方案2:把遞歸組件拆成左右板塊,左邊先遍歷同級的node節點,右邊的數據渲染是經過選中上一級的node節點來控制下一級的node節點。(ps:同級的node節點遍歷)

其實總結起來就是:要深度遍歷仍是廣度遍歷呢?(ps:最終的方案留個疑問,下文講述...)

設計組件

這裏是經過一個遞歸組件CascaderItem和搜索過濾filterItem組件以及一個父組件Cascader來完成需求。

先從佈局開始

擬稿組件的佈局是左右面板,開發這個組件我是使用flex佈局,我最終是使用方案2來遍歷數據渲染。 方案1在功能的實現上是沒有問題的,可是就佈局來看會有必定的缺陷的,由於方案1是根據一個node節點做爲一個面板。

方案2的組件模板:

left面板是同級節點的循環遍歷,right部分是組件自身引用自身,那麼就成了一個遞歸組件。

組件屬性的設計

這個組件的屬性設計,我是經過props屬性進行傳遞的。

遞歸組件CascaderItem的屬性有:optionslevel(ps:表示當前是哪一級)、changeValToStrisCheckboxisInputreverseChoice

而父組件Cascader的屬性除了上面的屬性以外還有:filterablevalue(ps:雙向綁定,下文講述)、iptProps

具體各個屬性的含義可查看源碼註釋,這裏再也不作講述了...

遞歸組件實現思路

這裏是經過一個計算屬性showRightItem來控制是否須要顯示隱藏子節點的面板(ps:遞歸的終止的條件)。而這個計算屬性依賴於一個響應式數據selected數組(ps:被選中的節點)。經過判斷選中的該級節點是否有children屬性來控制showRightItem返回值。

這個selected是經過父組件Cascader傳給子組件CascaderItem。在這裏我是經過selected.sync傳遞屬性,而且當用戶點擊node節點時能夠觸發update:selected事件讓父組件的數據發生改變。

捕獲用戶行爲

當用戶點擊node的節點時,不只僅要觸發update:selected事件的。要在這個用戶行爲的函數上處理一些其餘的邏輯。等因此的邏輯都完成以後再觸發事件通知父組件。

涉及到的邏輯以下:

1.判斷處理用戶點擊行爲是正選仍是反選。

2.操做selected數組,該級節點的下一級節點數據刪除。由於上一級節點被切換了,那麼下一級節點要被刪除,實現切換數據視圖一致的效果。

3.選中的該級節點是否有children屬性,若是有則須要將下級的第一位pushselected數組,直到下級的第一位沒有children屬性爲止。

當用戶在每一級進行搜索的時,觸發的是input事件。要在這個用戶行爲上作當前級下的數據過濾。

搜索當前級下的數據時,下一級的面板的數據是沒法預知的。爲了解決搜索的父節點的數據與當前子面板的數據不相關聯(ps:它可能還停留在上一個節點的子節點數據),讓用戶感到困惑。

這裏是經過一個開關進行控制,在用戶搜索時將下一個面板隱藏。等到用戶肯定搜索的目標時再進行展開。

好了,到這裏遞歸組件大體的邏輯完成了。具體的實現可查看源碼...

父組件的實現思路

父組件是暴露給用戶使用的組件。它相似總池子將任務分配給不一樣的子組件。這裏經過用戶傳來的filterable屬性來肯定是不是使用遞歸組件CascaderItem仍是filterItem組件。

秉承着高內聚低耦合的思想,組件對外暴露onChange事件以及v-model屬性。

當選中的節點發生變化時觸發onChange事件。v-model屬性實現數據的雙向綁定,內部觸發input事件及時更新用戶綁定的數據。

父組件相似總池子,它還負責處理一些數據。主要涉及到的邏輯以下:

1.初始化數據,將樹形結構數據新增pathObjchecked屬性。(ps:pathObj屬性是用來記錄上下級節點的關係,checked這個屬性是服務於遞歸組件的checkbox框)

2.將樹形數據扁平化,爲搜索時提供總數據。

3.初始化selected數組,根據用戶傳入的值初始化selected數據。

具體的數據處理邏輯如何實現可查看源碼以及源碼註釋...

使用Cascader

以下圖:

原本想錄個操做組件的小視頻,無奈我還不知道哪款軟件😢 ̄□ ̄||(ps:更可能是由於懶😝) 煩請各位大佬下載源碼自行體驗哈~

源碼地址

Cascader

覆盤

完成業務需求並不難,可能有不少種的方式能夠達到目的。我以爲更多的是在開發過程當中的思考以及如何設計是寫代碼一開始很重要的一部分。

在開發這個組件的時候,和小夥伴有個小插曲碰撞:就是用戶選中節點數據合不合理的問題?

怎麼理解呢? 我所理解的開發組件是給用戶操做的,選中節點數據是否符合業務需求我認爲是另一個層面上業務邏輯問題了,應該另作判斷,另外封裝規則。(ps:我想你們都有本身的理解和想法吧~)

不足:目前只支持單選功能,組件還能夠再開發多選功能(ps:後續有時間迭代,敬請期待...)

團隊協做,避免不了你須要在別人的代碼基礎上去實現新的功能。談談在已有的功能基礎上去迭代新的需求,平常你是如何實踐的呢?

總結

在開發的過程中,我仍是以爲封裝組件設計組件是有必要的,爲項目管理、後續的迭代添加不同的色彩。

這篇簡文是lin年前最後一篇的總結了,對各大掘友有幫助的話但願賞個 star ~

最後,提早祝你們新年快樂,新的一年萬事順意~

相關文章
相關標籤/搜索