本文首發於 歐雷流。因爲我會時不時對文章進行補充、修正和潤色,爲了保證所看到的是最新版本,請閱讀 原文。
在軟件開發中,研發效率永遠是開發人員不斷追求的主題之一。於公司而言,在競爭激烈的互聯網行業中,產出得快和慢也許就決定着公司的生死存亡;於我的而言,效率高了就能夠少加班,多出時間去提高本身、發展愛好、陪伴家人,工做、生活兩不誤。前端
提高效率的途徑,無外乎就是「方法」和「工具」。以一個開發者的思惟來想,就是將工做內容進行總結、概括,從一組類似的工做內容中提煉共同點,抽象出解決這一類問題的方法,從而造出便於在從此的工做中更爲快速解決這類問題的工具。這個「工具」能夠是個函數、組件、中間件、插件,也能夠是 IDE、其餘開發工具的擴展,甚至是語言。web
在現代前端開發中,若是去問一個業務前端開發:「如何提高團隊開發效率?」對方所回答的內容中,極有可能會出現「組件庫」。沒錯,在前端工程化趨近完善的今天,在近幾年 React、Vue 等組件化庫/框架的影響下,面向組件開發的思惟方式早已深刻人心。前端工程化
如今,組件庫已是一個前端團隊的必備設施了,長遠來看,團隊必定且必需要有本身的組件庫。開源的第三方組件庫再好,對於一家企業的前端團隊來講也只是短時間用來充飢的,由於它們沒法徹底知足一家公司的業務場景,而且出於多終端支持的考慮,一定要進行二次開發或者自研。框架
組件庫有了,團隊和公司中推廣的效果也不錯,絕大多數的人都在用。使用組件開發頁面相對 jQuery 時代要每塊功能區都得從 <span>
、<div>
等 HTML 標籤碼起來講確實提高了效率,然而有限;要搞出頁面須要反覆去引入組件,而後組合拼裝出來,就像工廠流水線上的工人拼裝零件,仍然要去作不少重複動做。frontend
只要以爲當前的開發方式重複的動做多了,就表明還能繼續提效,得想個法子減小重複無心義動做。ide
面向組件的開發方式,是現代前端頁面開發提效的初級階段,也是一個團隊所要必經的階段。函數
在以前寫的文章中有段話——工具
組件能夠很簡單,也能夠很複雜。按照複雜程度從小到大排的話,能夠分爲幾類:組件化
- 基礎組件;
- 複合組件;
- 頁面;
- 應用。
對,不用揉眼睛,你沒有看錯!佈局
站在更高的角度去看,「頁面」和「應用」也是一種「組件」,只不過它們更爲複雜。在這裏我想要說的不是它們,而是「基礎組件」和「複合組件」。
——歐雷《我來聊聊面向組件的前端開發》
文中提到了「頁面」和「應用」也能夠看做是種「組件」。雖然與當時的想法有些差別,但本文的內容就是要在那篇文章的基礎上簡單聊聊在「頁面」層面的提效。
通常來講,「頁面」是用戶所能看到的最大、最完整的界面,若是能在這個層面有個很好的抽象方案,在作業務開發時與單純地面向組件開發相比,應該會有更大的提效效果。
GUI 發展了幾十年,人機交互的圖形元素及佈局方式已經相對固定,只要不是出現像 Google Glass 之類的革命性交互設備,就不會發生重大改變。在業務開發中界面形式更是千篇一概,尤爲是 web 頁面,尤爲是中後臺系統的 web 頁面,必定能夠經過什麼方式來將這種「千篇一概」進行抽象。
試着來回想下,本身所作過的中後臺系統的絕大部分頁面是否是我所描述的這樣——
頁面總體是上下或左右佈局。若是是上下佈局的話,上面是頁頭,下面的左側可能有帶頁面導航的側邊欄,或者沒有側邊欄直接將頁面導航所有集中在頁頭中,剩餘區域是頁面主體部分,承載着這個頁面的主要數據和功能;若是是左右佈局,左側毋庸置疑就是有頁面導航的側邊欄,頁頭跑到了右側上面,其他是頁面主體。
中後臺系統的主要功能就是 CRUD,即業務數據的增刪改查,相對應的頁面展示及交互形式就是列表頁、表單頁和詳情頁。列表頁彙總了全部業務數據的簡要信息,並提供了數據的增、刪、改和更多信息查看的入口;表單頁肩負着數據新增和修改的功能;詳情頁可以看到一條業務數據記錄最完整的信息。
每新增一個業務模塊,就要又寫一遍列表頁、表單頁和詳情頁……反覆作這種事情有啥意思呢?既然這三種頁面會反覆出現,那乾脆封裝幾個頁面級別的組件好了,有新需求的時候就建幾個頁面入口文件,裏面分別引入相應的頁面組件,傳入一些 props
,完活兒!
這種方式看起來不錯,然而存在幾個問題:
我須要一種既能看一眼就理解內容結構和關係,又具有較好擴展性,還能減小重複代碼和無心義動做的方式——是的,兜了一個大圈子終於要進入正題了——面向模板開發。
面向模板的前端開發有三大要素:模板;節點;控件。
我所說的「模板」的主要做用是內容結構的描述以及頁面的配置,觀感上與 XHTML 相近。它主要具有如下幾個特徵:
爲何不選擇用 JSON 或 JSX 來描述和配置頁面?由於模板更符合直覺,更易讀,而且中立。用模板的話,一眼就能幾乎不用思考得看出都有啥,以及層級關係;若是是 JSON 或 JSX,還得在腦中進行轉換,增長心智負擔,而且拼寫起來相對複雜。Vue 上手如此「簡單」的緣由之一,就是它「符合直覺」的設計。
要使用模板去描述頁面的話,就得自定義一套具備抽象語義的標籤集。
頁面的總體佈局能夠用以下模板結構去描述:
<layout> <header> <title>歐雷流</title> <navs /> </header> <layout> <sidebar> <navs /> </sidebar> <content>...</content> </layout> <footer>...</footer> </layout>
看起來是否是跟 HTML 標籤很像?但它們並非 HTML 標籤,也不會進行渲染,只是用來描述頁面的一段文本。
總體佈局能夠描述了,但承載整個頁面的主要數據和功能的主體部分該如何去描述呢?
在上文中提到,咱們習慣將中後臺系統中與數據的增刪改查相對應的頁面稱爲「列表頁」、「表單頁」和「詳情頁」。雖然它們中都帶有「頁」,但真正有區別的只是整個頁面中的一部分區域,一般是頁面主體部分。它們能夠被分別當作是一種視圖形式,因此能夠將稱呼稍微改變一下——「列表視圖」、「表單視圖」和「詳情視圖」。通常狀況下,表單視圖和詳情視圖長得基本同樣,就是一個能編輯一個不能,能夠將它們合稱爲「表單/詳情視圖」。
「視圖」只描述了一個數據的集合該展現成啥樣,並無也無法去描述每一個數據是什麼以及長啥樣,須要一個更小粒度的且可以去描述每一個數據單元的概念——「字段」。這樣一來,用來描述數據的概念和模板標籤已經齊活兒了:
<view> <field name="name" label="姓名" /> <field name="gender" label="性別" /> <field name="age" label="年齡" /> <field name="birthday" label="生日" /> </view>
雖然數據可以描述了,但還有些欠缺:表單/詳情視圖中想將字段分組展現無法描述;對數據的操做也沒有描述。爲了解決這兩個問題,再引入「分組」和「動做」。這下,表單/詳情視圖的模板看起來會是這樣:
<view> <group title="基本信息"> <field name="name" label="姓名" /> <field name="gender" label="性別" /> <field name="age" label="年齡" /> <field name="birthday" label="生日" /> </group> <group title="寵物"> <field name="dogs" label="🐶" /> <field name="cats" label="🐱" /> </group> <action ref="submit" text="提交" /> <action ref="reset" text="重置" /> <action ref="cancel" text="取消" /> </view>
模板很好地解決了內容結構描述和配置的問題,但如何去動態地調整結構和更改配置呢?在日常的業務頁面開發時也許不會太凸顯出問題,但碰到流程表單設計或頁面可視化編輯這種靈活性很高的需求時,問題就會被暴露出來了。
在這裏,我要將定義好的標籤集所拼成的模板解析成節點樹,經過更改樹的結構和節點的屬性去影響頁面最終的呈現效果。每一個節點都會有節點的基本信息、對應標籤的屬性和一些節點操做方法:
{ name: "field", tag: "field", attrs: { name: "name", label: "姓名" }, parent: {}, children: [], remove: function() {}, insert: function() {} }
在頁面模板化且節點化以後,理想狀況下,頁面長啥樣已經不受如 React、Vue 等運行時技術棧的束縛,控制權徹底在解析模板所生成的節點樹上,要想改變頁面的視覺效果時只需更改節點便可。
頁面內容的描述經過模板來表達了,頁面內容的控制權集中到節點樹中了,那麼頁面內容的呈如今這種體系下應該如何去作呢?負責這塊的,就是接下來要說的面向模板開發的第三大要素——控件。
「控件」這個詞不新鮮,但在我所說的這個面向模板開發的體系中的含義,須要被從新定義一下:「控件」是一個可複用的,顯示的信息排列可由用戶改變的,能夠進行交互的 GUI 元素。
在這個面向模板開發的體系中,模板和節點樹徹底是中立的,即不受運行時的技術棧所影響;而控件是創建在運行時技術棧的基礎之上,但沒必要限於同一個技術棧。也就是說,可使用 React 組件,也能夠用 Vue 組件。
每一個控件在使用前都須要註冊,而後在模板中經過 widget
屬性引用:
<view widget="form"> <group title="基本信息" widget="fieldset"> <field name="name" label="姓名" widget="input" /> <field name="gender" label="性別" widget="radio" /> <field name="age" label="年齡" widget="number" /> <field name="birthday" label="生日" widget="date-picker" /> </group> <group title="寵物" widget="fieldset"> <field name="dogs" label="🐶" widget="select" /> <field name="cats" label="🐱" widget="select" /> </group> <action ref="submit" text="提交" widget="button" /> <action ref="reset" text="重置" widget="button" /> <action ref="cancel" text="取消" widget="button" /> </view>
這樣,一個面向模板開發的普通表單頁出來了!
面向模板的開發方式很好,可以大幅度提升業務前端開發效率,必定程度上減小了業務系統的搭建速度;做爲核心的模板和節點樹是保持中立的,大大下降了運行時技術棧的遷移成本,且可以應對多端等場景。
面向模板的開發方式初期投入成本很高,標籤集、模板解析和控件註冊與調用機制等的設計和實現須要較多時間,而且這僅僅是視圖層,邏輯層也須要作出相應的變化,不能簡單地用 props
和事件綁定進行處理了。
這個體系建成以後,在業務開發上會很簡單,但機制理解上會增長部分開發人員的心智負擔。
爲了效率,一家公司裏的業務前端開發到最後必定是面向模板,而非面向組件。