用1100天做一款通用的管理後臺框架

2023-10-31 09:00:51

前言

去年年底,我寫了一篇《如何做好一款管理後臺框架》的文章,這是我對開發 Fantastic-admin 這款基於 Vue 的中後臺管理系統框架兩年多時間的一個思考與總結。

很意外這麼一篇標題平平無奇的文章能收穫 30k 的瀏覽以及 600 多個收藏,似乎大家對這種非乾貨的文章也挺感興趣。於是在這個三年的時間點上(沒錯,也就是1100天),我打算繼續出來和大家嘮嘮,這一年我又做了些什麼事,或者說,如何把一款好的後臺框架變得通用?

題外話:如果你對我以前的文章感興趣,可以點我頭像進入主頁檢視;如果你期待我以後的文章,也可以點個關注。

痛點

因為 Fantastic-admin 是基於 Element Plus 這款 UI 元件庫進行開發的,於是今年我陸陸續續被問到一些問題:

  • 以後會有 Ant Design Vue 版本麼?會有 Naive UI 版本麼?會有 …… 版本麼?
  • 我們公司/團隊有一套內部的 UI 元件庫,可以在 Fantastic-admin 裡使用麼?會和 Element Plus 有衝突麼?
  • 我們有一些老專案希望遷移到 Fantastic-admin 上來,但 UI 元件庫用的不是 Element Plus ,有什麼辦法麼?

類似的問題一多,我也在思考一個問題:我的這款框架是不是被 Element Plus 綁架了?如果開發者在做技術選型的時候,因為 UI 元件庫不符合預期,而將我的框架篩掉,這是我不希望看到的結果。

基於這個潛在隱患,我開始計劃對框架進行轉型。

方案

方案一

既然開發者對 UI 元件庫有各自的偏好,我又想拉攏這部分開發者,那是不是多出幾套不同 UI 元件庫版本的就可以了呢?沒錯,這是我最開始冒出來的念頭。

我參考了一些同類產品的做法,儘管它們把不同 UI 元件庫版本做得很像,但在使用體驗過程中,還是會帶來操作上的割裂感。並且因為無法抹平不同 UI 元件庫在 API 上的差異,導致在框架功能上,不同版本之間也會有一些差異。

你可以分別對比左右或者上下兩張圖,包括左側導航欄的樣式、導航收起/展開按鈕的位置、右側專案設定中提供的功能等,都能明顯發現它們的差異。

雖然這可能不是什麼大問題,但我認為視覺風格上的統一是能幫助產品提高識別度的。就比如上面 4 款基於不同 UI 元件庫開發的後臺框架,雖然它們屬於同一個產品,但如果我不告訴你,你未必能通過圖片確定它們師出同門。

其次就是後臺框架提供的功能不統一,這裡面有一定的原因是因為 UI 元件庫導致的。試想一個場景,如果你要從 Element Plus 版本的後臺,遷移到 Ant Design Vue 版本的後臺,框架的組態檔是否能原封不動的複製過去?如果導航(路由)資料是後端返回的,資料結構能否保持完全一致,後端無需做任何修改?因為不同 UI 元件庫對選單元件的使用方式是完全不同的,比如 Element Plus 是需要手動拼裝的,而 Naive UI 則是資料驅動的,只需要傳入一個樹形結構的資料給元件即可。如果資料結構無法保證一致,就會增加遷移和學習的成本。

最後就是我的一點私心,因為多一個 UI 元件庫的版本,勢必會佔據我更多的業餘時間,如果同時維護 4、5 個版本,那我大概下班後的所有時間都要投入到其中,並且如果未來又有新的 UI 元件庫成為流行,那就又多一個版本的維護,這並不是一個可持續發展的方案。

方案二

既然上一個方案不符合我的期望,於是我開始思考,框架本身能不能不依賴這些 UI 元件庫?如果框架本身不依賴於三方的 UI 元件庫,那開發者不就可以根據需要自行引入想要的元件庫了麼。

就如上圖,主/次導航和頂欄是屬於框架的部分,而這部分其實並沒有用到太多 UI 元件庫提供的元件,以 Element Plus 舉例,我統計了一下目前 Fantastic-admin 用到的元件:

  • Menu 選單(主/次導航)
  • Breadcrumb 麵包屑(頂欄)
  • Popover 氣泡卡片(頂欄右側的工具列)
  • Dropdown 下拉式選單(頂欄右側的工具列)
  • Drawer 抽屜(應用設定)
    • Message 訊息提示
    • Button 按鈕
    • Input 輸入框
    • Radio 單選框
    • Select 選擇器
    • Switch 開關
    • …(等等表單類元件)

可以看到,雖然抽屜元件裡用了很多表單類的元件,但這部分元件都是在應用設定裡使用的,而應用設定這個模組,主要是方便線上測試框架提供的各種功能,在實際業務開發中,是完全不需要這個模組的。

所以初步算下來,後臺框架真正依賴於 Element Plus 實現的元件就只有 4 個:

  • Menu 選單
  • Breadcrumb 麵包屑
  • Popover 氣泡卡片
  • Dropdown 下拉式選單

那我為什麼不找一些獨立的第三方外掛替代呢?是的,這是我第二個方案,就是找一些獨立的外掛替換 UI 元件庫中的元件。但問題也立馬迎面而來,就是偌大一個 Github ,居然找不到符合我需求和審美的外掛。

比如選單外掛,我希望它和 Element Plus 裡的選單元件在功能上沒有太大差異,支援水平/垂直模式、支援摺疊收起、支援設定預設啟用選單、支援預設展開等。

比如麵包屑外掛,或許是因為這個外掛功能太簡單,並且大部分 UI 元件庫都有提供,在 Github 能搜到獨立的麵包屑外掛很少,搜到的也基本上是 N 年前的上傳的,既沒有人維護,風格樣式也很醜。

這個方案似乎也行不通……嗎?

方案三

雖然方案二在實施的第一步就撲街了,但有一點思路還是正確的,就是讓框架本身不依賴於三方 UI 元件庫。既然網上搜不到合適的外掛,那我為什麼不自己寫一個呢。

比如麵包屑,這是一個很簡單的功能,任何前端初學者應該都可以寫一個麵包屑元件。

而氣泡卡片和下拉式選單我沒有計劃自己寫,因為找到了一個還不錯的外掛 Floating Vue,它由 Vue 團隊核心人員開發並維護,並且最重要的是它支援自定義樣式,意味著我可以將它魔改成想要的樣子,儘可能和我的框架在視覺風格上保持統一。

最後一個比較難啃的骨頭就是選單,因為找不到合適的替代品,自己寫的話又比較有挑戰,雖然我有一點實現思路,但不多。當然最終還是決定自己寫一個,因為覺得三方 UI 元件庫這麼多,實在寫不出來我就去讀他們原始碼,總不能每一個原始碼我都讀不懂吧。

這 4 個元件的替換方案確定後,剩下就是抽屜元件和它裡面的一些表單元件了,這些要怎麼解決呢?這會我想到了 Headless UI ,它是完全無樣式的 UI 元件庫,通過與 Tailwind CSS / UnoCSS 整合使用,可以快速構建出屬於自己風格的元件。

但是 Headless UI 提供的元件非常有限,並不能覆蓋我需要的表單元件。不過它的設計給了我啟發。表單元件我並不需要非常複雜的功能,原生的表單控制元件其實就能滿足我的使用需求,只是原生的樣式比較醜,和我想要的風格不統一,那我只需要給他們客製化一套統一的風格就可以了,也就寫一套原子化的 CSS 樣式。

於是,方案敲定,開始實操。

實操

我決定從易到難開始處理,因為這樣在初期能快速看到進度推進,也避免一上來就被一個選單功能卡住好幾天,甚至十幾天都沒有進展,打擊到自己的信心。

1. 麵包屑

和預期一樣,並沒有什麼難度,很輕鬆就實現了。只不過目前還是保持和 Element Plus 一樣的使用方式,就是需要手動拼裝,後期計劃改成資料驅動的使用方式。

2. 氣泡卡片 & 下拉式選單

這部分參考了 nuxt/devtoolsFloating Vue 的自定義樣式,以及 nuxt/ui 中下拉式選單的樣式風格,最終形成了我自己滿意的風格

3. 抽屜

使用了 Headless UI 中的 Dialog 元件,因為它和抽屜元件有相同的互動方式,它們都是在遮罩層上展示內容,只不過 Dialog 更多時候是居中展示,而抽屜則是在左右兩側展示。

其次在使用過程中,發現 Headless UI 中的 Transition 元件是一個驚喜。雖然 Vue 本身就有提供 <transition> 元件用於處理過渡動畫,但有一個場景會比較難處理,官方的描述是:

This technique is needed when you want to coordinate different animations for different child elements – for example, fading in a Dialog's backdrop, while at the same time sliding in the contents of the Dialog from one side of the screen.
當您要為不同的子元素協調不同的動畫時,就需要使用這種技術,例如,在淡入對話方塊背景的同時,從螢幕的一側滑入對話方塊的內容。

這說的不就是抽屜元件麼?於是按照官方的範例,修改了整體風格,最終效果也就出來了。

4. 表單元件

之前的計劃是修改原生表單控制元件的樣式,但在開發過程中發現會有一定的侷限性。比如 <select> 無法控制彈出選項框的樣式,我的解決辦法就是用 Floating Vue 封裝模擬一個 select 元件。

同時也在開發過程中發現了一些被遺漏元件,於是邊做邊補,最終大概做了 10 多個元件。雖然看著不少,它們都秉持著最小可用的狀態。什麼意思呢?就是我不會給它們設計太多的 API ,因為它們的定位和三方 UI 元件庫不同,它們只要滿足框架本身使用即可,用不到的 API 不會進行開發。並且使用上也不會有太大負擔,如果不是對框架進行二次開發,開發者是可以完全不用關注這部分元件。

5. 選單

選單元件確實是個難啃的骨頭,我差不多用了 3 周的晚上時間去開發。

第一週,按照自己的思路徒手擼,做到一半卡殼,做不下去了;

第二週,開始看 Element Plus 、Naive UI 、Ant Design Vue 裡選單的原始碼;

Ant Design Vue 的沒看懂,放棄;

Naive UI 的看到一半發現核心實現被作者封裝到 treemate 這個獨立包中了,雖然這個包是開源的,目的也是針對樹形結構的一體化解決方案。但我粗略看了一遍檔案,感覺有點大材小用,因為它有很多 API 我是用不到的,而我對選單元件又有一些自己的想法,不確定是否它這個包能否滿足我的需求,放棄;

最後選擇看 Element Plus 的,通過在本地一點點列印資料,大概理解了實現思路,但元件遞迴呼叫,父子元件通過 provide / inject 傳遞資料和函數的方式,資料狀態的變動也是一層層向上級元件通知,直到通知到頂層元件,在我看來有點不太優雅,如果資料能統一在頂層元件裡操作就好了。其次我的計劃是寫一個資料驅動的選單元件,而不是像 Element Plus 需要手動拼裝的,所以雖然我大致看懂了 Element Plus 選單元件是怎麼實現的,但在我自己實現的時候,還是有很大的不同,能參考的程式碼並不多。

這部分的開發總結,我可能會在以後單獨寫一篇文章詳細說說,因為這部分也是整個方案中唯一的難點。

第三週,因為實現思路大致有了,所以開發上就沒有太多的卡殼,最終結果也還不錯,基本達到了我的需求。

同時因為元件完全可控,順帶解決了之前使用 Element Plus 選單元件上無法解決的 bug ,比如當選單收起時,彈出的懸浮選單如果數量過多,超出螢幕高度,超出的部分就無法檢視了,就像這樣:

但是現在則會有卷軸,使用體驗上更舒服。

驗證

至此,我的後臺框架已經擺脫對 Element Plus 的依賴,接下來就需要驗證一下是否可以方便的替換成其他 UI 元件庫。

我分別用 Ant Design Vue 、Arco Design Vue 、Naive UI 、TDesign 這四款熱度比較高的元件庫進行了驗證:

Ant Design Vue Arco Design Vue Naive UI TDesign

結果還是很滿意的,都能夠順利替換,並且替換過程並沒有花費很多時間,一個小時內就可以替換成功。

由於登入頁這個特殊的存在,替換元件庫後是需要對其用到的 Element Plus 元件進行手動修改的,這部分會比較花時間,因為會涉及到表單驗證之類的東西,不同元件庫的寫法差異還是比較大的。

詳細的替換步驟可以在 Fantastic-admin 官方檔案裡找到。

回顧

讓我們重新看下一開始的痛點是否都解決了麼:

  • 以後會有 Ant Design Vue 版本麼?會有 Naive UI 版本麼?會有 …… 版本麼?

    雖然不會有,但可以自己動手,根據教學將預設的 Element Plus 替換成你想要的 UI 元件庫就可以了

  • 我們公司/團隊有一套內部的 UI 元件庫,可以在 Fantastic-admin 裡使用麼?會和 Element Plus 有衝突麼?

    不會有衝突,現在可以徹底移除 Element Plus ,安裝並使用自己的 UI 元件庫

  • 我們有一些老專案希望遷移到 Fantastic-admin 上來,但 UI 元件庫用的不是 Element Plus ,有什麼辦法麼?

    可以用 Fantastic-admin 原始碼先進行 UI 元件庫的替換,之後再將老專案的業務程式碼逐部遷移

除了解決這些痛點,甚至還有新收穫:

  • 幫助公司/企業打造視覺風格統一的產品,提高產品辨識度

    大公司可能有不止一個專案團隊,不同專案團隊的技術偏好可能無法完全統一,導致開發的後臺長得也千變萬化。但即使在這種情況下,使用 Fantastic-admin 依舊可以保持整體視覺風格上的統一。

  • 近乎於 0 的上手成本

    因為後臺框架始終都只有一套,開發者不會因為切換 UI 元件庫後,要重新瞭解後臺框架的使用

  • 維護成本更低,產品生命週期更長

    這一點是對我自己說的,不管未來會出現多少個新的 UI 元件庫,我都不需要去新增一個版本進行單獨維護;或者 Element Plus 如果有一天停止維護了,我的產品也不會因此進入了死亡倒計時

總結

文章寫到這裡,差不多就結束了,雖然閱讀一遍可能只花了不到10分鐘,但為了做成這件事,我大概從今年 6 月份就開始構思了,也是花了蠻多的精力,所以很感謝你的耐心。

當一款產品做到第 4 個年頭,周圍大部分同類產品都進入到半停更的狀態,這一年裡我經常思考如何延長產品的生命週期,如何讓更多人來使用,而這篇文章就是對我自己今年的一個總結,也是一份答卷,希望大家能喜歡。

另外,Fantastic-admin V4.0 已經正式釋出,感興趣的朋友可以來看看,或許你的下一個專案,就可以用上了。