我來聊聊面向模板的前端開發

本文首發於 歐雷流。因爲我會時不時對文章進行補充、修正和潤色,爲了保證所看到的是最新版本,請閱讀 原文

在軟件開發中,研發效率永遠是開發人員不斷追求的主題之一。於公司而言,在競爭激烈的互聯網行業中,產出得快和慢也許就決定着公司的生死存亡;於我的而言,效率高了就能夠少加班,多出時間去提高本身、發展愛好、陪伴家人,工做、生活兩不誤。前端

提高效率的途徑,無外乎就是「方法」和「工具」。以一個開發者的思惟來想,就是將工做內容進行總結、概括,從一組類似的工做內容中提煉共同點,抽象出解決這一類問題的方法,從而造出便於在從此的工做中更爲快速解決這類問題的工具。這個「工具」能夠是個函數、組件、中間件、插件,也能夠是 IDE、其餘開發工具的擴展,甚至是語言。web

面向組件

在現代前端開發中,若是去問一個業務前端開發:「如何提高團隊開發效率?」對方所回答的內容中,極有可能會出現「組件庫」。沒錯,在前端工程化趨近完善的今天,在近幾年 React、Vue 等組件化庫/框架的影響下,面向組件開發的思惟方式早已深刻人心。前端工程化

組件庫提效有限

如今,組件庫已是一個前端團隊的必備設施了,長遠來看,團隊必定且必需要有本身的組件庫。開源的第三方組件庫再好,對於一家企業的前端團隊來講也只是短時間用來充飢的,由於它們沒法徹底知足一家公司的業務場景,而且出於多終端支持的考慮,一定要進行二次開發或者自研。框架

組件庫有了,團隊和公司中推廣的效果也不錯,絕大多數的人都在用。使用組件開發頁面相對 jQuery 時代要每塊功能區都得從 <span><div> 等 HTML 標籤碼起來講確實提高了效率,然而有限;要搞出頁面須要反覆去引入組件,而後組合拼裝出來,就像工廠流水線上的工人拼裝零件,仍然要去作不少重複動做。frontend

只要以爲當前的開發方式重複的動做多了,就表明還能繼續提效,得想個法子減小重複無心義動做。ide

面向組件的開發方式,是現代前端頁面開發提效的初級階段,也是一個團隊所要必經的階段。函數

更高層面的提效

在以前寫的文章中有段話——工具

組件能夠很簡單,也能夠很複雜。按照複雜程度從小到大排的話,能夠分爲幾類:組件化

  1. 基礎組件;
  2. 複合組件;
  3. 頁面;
  4. 應用。

對,不用揉眼睛,你沒有看錯!佈局

站在更高的角度去看,「頁面」和「應用」也是一種「組件」,只不過它們更爲複雜。在這裏我想要說的不是它們,而是「基礎組件」和「複合組件」。

——歐雷《我來聊聊面向組件的前端開發

文中提到了「頁面」和「應用」也能夠看做是種「組件」。雖然與當時的想法有些差別,但本文的內容就是要在那篇文章的基礎上簡單聊聊在「頁面」層面的提效。

通常來講,「頁面」是用戶所能看到的最大、最完整的界面,若是能在這個層面有個很好的抽象方案,在作業務開發時與單純地面向組件開發相比,應該會有更大的提效效果。

GUI 發展了幾十年,人機交互的圖形元素及佈局方式已經相對固定,只要不是出現像 Google Glass 之類的革命性交互設備,就不會發生重大改變。在業務開發中界面形式更是千篇一概,尤爲是 web 頁面,尤爲是中後臺系統的 web 頁面,必定能夠經過什麼方式來將這種「千篇一概」進行抽象。

試着來回想下,本身所作過的中後臺系統的絕大部分頁面是否是我所描述的這樣——

頁面總體是上下或左右佈局。若是是上下佈局的話,上面是頁頭,下面的左側可能有帶頁面導航的側邊欄,或者沒有側邊欄直接將頁面導航所有集中在頁頭中,剩餘區域是頁面主體部分,承載着這個頁面的主要數據和功能;若是是左右佈局,左側毋庸置疑就是有頁面導航的側邊欄,頁頭跑到了右側上面,其他是頁面主體。

中後臺系統的主要功能就是 CRUD,即業務數據的增刪改查,相對應的頁面展示及交互形式就是列表頁、表單頁和詳情頁。列表頁彙總了全部業務數據的簡要信息,並提供了數據的增、刪、改和更多信息查看的入口;表單頁肩負着數據新增和修改的功能;詳情頁可以看到一條業務數據記錄最完整的信息。

每新增一個業務模塊,就要又寫一遍列表頁、表單頁和詳情頁……反覆作這種事情有啥意思呢?既然這三種頁面會反覆出現,那乾脆封裝幾個頁面級別的組件好了,有新需求的時候就建幾個頁面入口文件,裏面分別引入相應的頁面組件,傳入一些 props,完活兒!

這種方式看起來不錯,然而存在幾個問題:

  • 沒有描述出頁面內容的結構,已封裝好的頁面組件對於使用者來講算是個黑盒子,頁面內容是什麼結構不去看源碼不得而知;
  • 若是新需求中雖然須要列表頁、表單頁和詳情頁,但與已封裝好的可以覆蓋大部分場景的相關組件所支持的頁面有些差別,擴展性是個問題;
  • 每來新需求就要新建頁面入口文件而後在裏面引入頁面組件,仍是會有不少無心義重複動做和重複代碼,時間長了仍是以爲煩。

我須要一種既能看一眼就理解內容結構和關係,又具有較好擴展性,還能減小重複代碼和無心義動做的方式——是的,兜了一個大圈子終於要進入正題了——面向模板開發。

面向模板

面向模板的前端開發有三大要素:模板;節點;控件。

富有表達力的模板

我所說的「模板」的主要做用是內容結構的描述以及頁面的配置,觀感上與 XHTML 相近。它主要具有如下幾個特徵:

  1. 字符所有小寫,多單詞用鏈接符「-」鏈接,無子孫的標籤直接閉合;
  2. 包含極少的具有抽象語義的標籤的標籤集;
  3. 以特定標籤的特定屬性的形式支持有限的輕邏輯。

爲何不選擇用 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 和事件綁定進行處理了。

這個體系建成以後,在業務開發上會很簡單,但機制理解上會增長部分開發人員的心智負擔。

爲了效率,一家公司裏的業務前端開發到最後必定是面向模板,而非面向組件。

相關文章
相關標籤/搜索