腾讯 Web UI 解决方案 QMUI Web —— 探索与沉淀
2019獨角獸企業重金招聘Python工程師標準>>>
作者簡介: 李浩成(Kayo),騰訊廣州研發部 UI 工程師。
經過長時間的打磨迭代,QMUI Web 作為騰訊廣研 QMUI 團隊的一個開源項目,正式發布到 Tencent Github。QMUI Web 是一個 Web UI 的解決方案,從零開始,由編碼規范,到組件和工具方法的制作,再到工作流的整合,不斷在迭代,也不斷在優化,走過了不少的路。趁著發布的機會,我們正好回顧這一路的探索過程,分享其中的點滴,也希望能借此讓大家更了解 QMUI Web。
背景
2014 年中,QMUI 團隊支持的主要項目是 QQ 郵箱,Web 端的郵箱是個龐大的項目,但其并沒有統一的 UI 基礎庫,多年的高速迭代使得項目的 UI 代碼變得混亂,各個模塊之間各自開發,除了在代碼層面表現出混亂和不可控之外,表現層面也并沒有很好地統一起來。因此,項目急需一套統一的團隊編碼規范以及一個 UI 基礎庫。 恰好,這個時候 Sass 等 CSS 預處理器已經發展成熟,自動化工作流的工作模式也日趨完善,因此,我們決定基于這些技術制作一套通用于不同項目的 Web UI 框架。框架的場景定位很明確:需要控制整體樣式,并且可以適應頻繁迭代打磨的大型項目。所以,這套即將誕生的 Web UI 框架的特性也很明確:需要方便地控制項目的整體樣式,應對頻繁的界面變動,并保持項目質量穩健。 此后經過三年的發展,QMUI Web 最終發展為包含編碼規范、樣式工具方法與樣式管理、內置工作流,配套的 GUI 桌面 App,以及擁有完整文檔的解決方案。
設計理念
在制作框架的過程中,我們把框架需要的特性進行整理和思考,形成了一套對于該框架的設計理念,在這些設計理念之中,最核心的關鍵為通用于多個項目,高效迭代和保持代碼穩健,框架的設計也遵循這三個核心點,體現在框架上,具體就是:
- 框架和組件需要剝離業務。作為 UI 框架,框架內整合的組件和樣式必須有能力剝離業務,才能跨項目使用。
- 能輕易控制整體樣式。需要高效地迭代項目,樣式的整體控制必不可少。
- 保持代碼穩健。
而具體到代碼層面,則可以歸納為兩個方面:
- Class-name 命名規范。
- 基礎樣式配置與半封裝組件。
Class-name 命名規范
作為一個 Web UI 框架,編寫代碼主要是 CSS 與 HTML,而提到 CSS 與 HTML 的編寫,首先要處理的是 Class-name 的命名,在過往的開發中,Class-name 的命名并沒有固定的規范,開發人員各自進行開發,一個項目經過長時間的迭代后,經常會遇到如命名沖突,命名混亂等問題,這使得項目的迭代變得笨重,也不好維護。因此,我們需要一套具有如下特點的 Class-name 命名規范:
- 命名有跡可循,容易編寫。
- 避免命名沖突,包括內部多人協作命名沖突,以及外部庫引入時的被動污染。
- 命名具有語義,能晰地描述整個頁面,方便理解上下文。
因此,最終 QMUI Web 制定了一套以命名空間為核心的命名方式,這個命名方式主要由“命名空間”,“業務與組件的拆分”,“精確表達 View”三個部分構成。
命名空間
一個 QMUI Web Class-name 應該包含一個命名空間,也是 Class-name 的開頭,如果是業務,則以業務內容為命名空間,如果是公共組件,則全局使用項目的名字(或縮寫)為命名空間。如一個名為 Demo 的項目,項目縮寫可以是 dm,那么該項目下的項目組件和公共類可以這樣命名: dm_btn(按鈕)、dm_icon(圖標)、dm_ipt(輸入框)、dm_toolbar(工具欄)。 邏輯模塊命名以具體業務作為前綴,如簡歷(resume)功能里面的非公共組件部分,以 resume_ 作為前綴(resume_mod、resume_text、resume_list),個人信息(profile)頁面的非公共組件部分,則可以以 profile_ 作為前綴(profile_statge、profile_stage_title)。 命名空間作為一種基礎的隔離,把組件與業務,以及不同的業務之間的 Class-name 命名隔離開來,避免沖突,而后父子元素之間逐級展開編寫,保證了項目內多人協助不易沖突,同時命名帶有語義,也方便理解和閱讀。
業務與組件的拆分
接著,QMUI Web 中把項目的代碼劃分為通用組件(跨項目的組件),項目全局組件(適用于某個具體項目),業務組件(適用于某個業務),以及業務邏輯代碼,這樣區分出4個顆粒度可以使得代碼更容易被組織和復用,一個模塊隨著設計元素迭代,也可以在這4個顆粒度之間進行迭代,從而使得模塊在迭代時會更加穩健。而 QMUI Web 框架中的組件應該只收納通用組件,即跨項目組件。
精準表達 View
精準表達 View 是指在命名 DOM 節點時要明確這是一個怎樣的 View,這里的 View 指的就是 UI 層面上這個元素表示的含義,常見的場景是,一個命名為 resume_head 的元素,在經歷多次迭代后實際在代碼中卻充當了頁腳,這樣的命名在多人協作時很容易給后面的開發者造成困擾,而精準表達 View 則要求我們明確一個 UI 元素的含義,并在命名時準確地表達。
基礎樣式配置與半封裝組件
前面的“Class-name 命名規范”主要是在規范層面上去實踐 QMUI Web 的核心理念,而接著更多地就是在代碼層面上去實踐了,主要包括三點:
- 半封裝組件,即面向項目的組件。
- 使用組合而不是繼承。
- 顆粒度的把控。
半封裝組件即面向項目的組件
前文提到,QMUI Web 把組件劃分為通用組件,項目全局組件,業務組件三種組件,而 QMUI Web 框架收納的則是通用組件,也是跨項目的組件,但每個項目的 UI 表現并無關聯,如何處理跨項目組件就成為了一個問題。為此,QMUI 在處理組件時采取的是“半封裝”的處理方式,QMUI 框架封裝的是代碼,所謂半封裝,即封裝那些與項目具體 UI 表現沒有必然聯系的代碼。例如按鈕組件,QMUI Web 中只封裝了文字居中對齊,鼠標手型,瀏覽器樣式重置,低版本 IE 兼容性處理等代碼,而常用的樣式如邊框、背景、字體表現等,都抽取成變量控制,這些組件的變量最終都匯集到一個配置表 Sass 文件中,配合全局的顏色變量、字體變量等變量,就可以做到跨項目抽取組件,每個新項目只需要關注具體 UI 表現而無需再處理各種常見的 UI 問題,同時方便地通過調整這些變量的值而快速修改整個項目的樣式。
組合而不是繼承
在處理組件時,繼承的方式是指一個組件類承擔復雜的功能,而組合的方式則是把組件類拆分成一個基類,以及多個子類,每個子類承擔的功能不重復,對于我們的主場景——頻繁迭代,保持穩健,顯然組合會更加適合,這種方式避免了在頻繁的迭代中需要不斷修改組件類,每次迭代只需要修改對應的子類即可。
顆粒度
對于組件的抽取,時常要考慮顆粒度的劃分,顆粒度本身就是一個比較開放性的問題,在這里與大家分享一些沉淀的經驗:
- 抽取組件以 UI 表現為區分,例如一個刪除按鈕,是以刪除 icon + 刪除文案作為內容的,但在表現上它就是一個帶 icon 的文字按鈕,因此就抽取出一個支持 icon 的文字按鈕,而不用只局限于按“刪除”這個業務來命名組件。
- 抽取組件可以選擇較大的顆粒度,也可以選擇較小的顆粒度。顆粒度較大的組件實現復雜,能對應復雜的場景,但擴展性也會因此下降,而顆粒度較小的組件則實現簡單,能輕松實現一個主場景,但又方便擴展,能靈活地應對變化。因此建議是像按鈕、輸入框、下拉菜單這類通常位于頁面 DOM Tree 末端的元素可以抽取成盡量簡單的組件,同時通過擴展的方式去處理各種場景差異。而其他復雜的組件則可以專注于一個業務,不必過多地考慮不同的場景,否則組件很容易變得難以維護。
以上便是 QMUI Web 具體的設計理念,通過命名規范、基礎樣式配置與半封裝組件來保證多人協作時的高效率與可維護性,也使得一個 UI 框架能為不同的項目服務。
具體組成
作為一個框架,QMUI Web 主要提供了四種能力來提升 UI 開發的效率與質量,對應前文提到的框架設計理念,QMUI Web 提供的這些功能都是為了幫助開發者方便地控制項目整體樣式,應對頻繁變動,同時保持代碼穩健。
基礎配置與組件
前文提到,框架中會有一份配置表,是各種 Sass 的變量,這些變量控制了一個網頁基本的字體樣式,鏈接顏色,通用組件的樣式配置等基礎樣式,在創建一個新項目時,應該先根據設計稿配置好這些信息,當這些信息配置完成,那么一個項目的基本樣式就可以快速實現了。例如下圖中這些配置屬于 QMUI 通用配置,通過修改這些配置則可以快速修改項目的字體策略、正文字體大小,鏈接顏色等 UI 常用的 CSS 屬性。
內置工作流
QMUI 中包含一個基于 gulp 的內置工作流,用于快速解決大量重復勞動力的工作,從而提升效率。QMUI 的 gulp 中預先實現了監控 Sass 文件并自動編譯和優化,雪碧圖處理,模板 include 能力(可以傳參和使用條件判斷),瀏覽器自動刷新,圖片壓縮,文件清理,文件合并以及自動變更等能力。
Sass 增強支持
QMUI 中提供了大量基于 Sass 的 CSS 預處理的方法,包括 CSS Reset,一些常見的 CSS 類(例如清除浮動),計算長度值的簡便方法(例如獲取 padding 在某個方向的值,計算兩個長度值的中間值),快速實現一些樣式效果的工具方法(例如實現 border 三角形,適應多倍屏幕的 1px 邊框等),這些都是用于提高樣式開發的效率和質量。
擴展組件
擴展組件并不是由 QMUI Web 的主源碼提供,而是由 Demo 提供,通常是因為這類組件結構較復雜,因此業務性無法很好地剝離,從而不能抽取成公共組件,因此這類組件就放在一個 Demo 頁,以參考組件的形式幫助開發。
GUI
我們提供了一個用于管理 QMUI Web 項目的桌面 App,在代碼層面它獨立于 QMUI Web 的源碼。它通過 GUI 界面處理 QMUI Web 的服務開啟/關閉,并提供了編譯提醒,出錯提醒,進程關閉提醒等額外的功能,在處理多項目,多分支時能更方便地進行開發。
優化和開源
在經歷較長時間的迭代后,QMUI Web 也逐漸完善起來,此時我們也開始將 QMUI Web 進行開源。開源意味著 QMUI Web 會進入更加全面的環境中去打磨,在框架的非主體內容如代碼規范、注釋、文檔上面也需要更費心思,考慮的點也需要更加周全。這對團隊來說無疑是個很好的機會,可以有更多的渠道審視框架,吸收建議,持續進行優化。
在加入開源的大環境后,我們從 Github、社區論壇中都獲取了不少建議,除了 bug 的反饋外,也指出了一些待完善的地方和提出一些優化的解決方案,從而使得 QMUI Web 注入了更多活力,因此我們也逐步進行了如“自動化測試用例”、“gulp 結構化”,“引入 SassDoc 自動化生成文檔”,“編譯 Sass 時引入增加更新”等優化,其中不少優化點我們也在項目的 Github Wiki 中進行了詳細的分享,有興趣的用戶可以自行瀏覽。
總結與展望
至此,QMUI Web 發展為現在這套完整的方案,也終于開源到 Github Tencent 與大家分享,我們期望通過開源與大家進行更多的交流,也使得 QMUI Web 進入更加全面的環境中去打磨,形成對代碼規范、注釋、項目文檔感謝公司與部門給我們提供了一個平臺,可以在大型項目中經歷迭代和沉淀。開源只是一個開始,我們后續仍會不斷進行探索和優化,期待更好的 QMUI Web。
關注 QMUI Web, 來 Github 給我們 star 吧!
https://github.com/Tencent/QMUI_Web
轉載于:https://my.oschina.net/u/3447988/blog/1531840
總結
以上是生活随笔為你收集整理的腾讯 Web UI 解决方案 QMUI Web —— 探索与沉淀的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Advanced Installer
- 下一篇: 走近RDD