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

来源:https://www.cnblogs.com/hooray/archive/2023/10/31/17799426.html
-Advertisement-
Play Games

在這個三年的時間點上,也就是1100天,我打算繼續出來和大家嘮嘮,這一年我又做了些什麼事,或者說,如何把一款好的後臺框架變得通用? ...


前言

去年年底,我寫了一篇《如何做好一款管理後臺框架》的文章,這是我對開發 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 已經正式發佈,感興趣的朋友可以來看看,或許你的下一個項目,就可以用上了。

新博客地址
hooray.github.io
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文記錄如何在Linux系統上進行MongoDB資料庫的導出和導入(備份和還原),Windows系統上的命令基本一樣,僅文件路徑不同。 ...
  • 本文分享自華為雲社區《華為雲GaussDB城市沙龍活動走進安徽,助力金融行業數字化轉型》,作者: GaussDB 資料庫 。 近日,華為雲GaussDB資料庫城市沙龍·安徽站圈層活動順利舉行。活動邀請了金融行業代表及伙伴,一起圍繞資料庫展開了金融行業數字化轉型解決方案與成功實踐交流,共同推動國內數據 ...
  • 背景 1、在ArkTS的架構中,沒有明確的可管理的載入請求狀態的腳手架,在進行網路請求過程中,無法簡單的進行交互響應。 2、參考Android中的LoadState寫了一個簡單的腳手架,以便在日常開發過程中,管理載入請求狀態和UI交互。 腳手架說明與源碼 1、狀態機LoadState 使用一個狀態機 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一,問題起因 最新在開發小程式的時候,調用微信小程式來獲取用戶信息的時候經常報錯一個問題 fail api scope is not declared in the privacy agreement,api 更具公告,是微信更新對應的隱 ...
  • 在建設博客的初期,我採用GitBook構建了編碼專家的專欄系統。GitBook是基於Node.js的靜態頁構建組件,可以將Markdown文檔渲染為靜態頁,支持插件擴展,使用非常簡單。由於它不支持深度的定製,使用了一段時間後,無法滿足我的要求了。有一天我看到某博客採用VuePress,簡潔美觀、功能... ...
  • 我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。 本文作者:修能 朝聞道,夕死可矣 何為 Molecule? 輕量級的 Web IDE UI 框架——Molecule 我們開源了一個輕量的 Web IDE UI 框架 ...
  • 環境說明 macOS 13.5 % sw_vers ProductName: macOS ProductVersion: 13.5 BuildVersion: 22G74 Brew % brew --version Homebrew 4.1.2-33-gc531a35 安裝 安裝 nvm 使用 br ...
  • 我的小冊 《CSS 技術揭秘與實戰通關》上線了,想瞭解更多有趣、進階、系統化的 CSS 內容,可以猛擊 - LINK。 在 CSS 還原拉斯維加斯球數字動畫 - 掘金 一文中,我們利用純 CSS,實現了一個非常 Amazing 的動畫效果: 其中一個核心點就是,我們利用瞭如下的代碼,在一個 DIV ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...