我所在的業(yè)務(wù)組,負責(zé)公司的多個類目(這些類目就如京東上不同的品類)的產(chǎn)品開發(fā)。這些不同類目的門店有不同的特定,要展示不同的信息,因此就要求錄入的東西是不同。但是顯然,我們不打算每一個類目都開發(fā)一遍,所以我們設(shè)計了一套可配置頁面解決方案和一套動態(tài)解析數(shù)據(jù)解決方案。這篇博客講述的是我們的可配置頁面解決方案。不過這個解決方案限制在APP的h5頁面上。
不過擔(dān)心泄露公司機密(然而并沒有),所以這里將會忽略一些業(yè)務(wù)相關(guān)的東西。而且舉的例子也和我所在的公司無關(guān)。希望讀者見諒(不服你來打我?。?/p>
在可配置頁面里面,我認為要解決的是三個核心問題:
- 頁面布局和樣式
- 頁面內(nèi)容——也就是數(shù)據(jù)
- 頁面的交互
下面將從這三個角度來探討。
需求特征和一些概念
首先來看一張圖:

這是我在淘寶上隨便截的圖,雖然它和我實際要解決的需求的圖看起來差別很大。我給它劃分成了不同的塊,并且標號了。整個圖,被稱為頁面。里面一個個標號的,被稱為組件(Component)。實際上,頁面也是一個組件,被稱為頂級組件,也被稱為根組件(root component)。這里的劃分標號并不完整,但是可以看出來一些:
- 整個頁面被認為是一個樹形結(jié)構(gòu),由不同的組件構(gòu)成。這種樹形結(jié)構(gòu)的劃分是依賴于個人的理解的。從圖里面,我劃分出來的樹形結(jié)構(gòu)大概是1和2是根的子節(jié)點,3和4是2的子節(jié)點,5是4的子節(jié)點;
- 組件由組件構(gòu)成,它們是遞歸構(gòu)建的。直到最小的組件,這一類的組件邏輯上將無法再被拆分,這一類的組件被稱為單元(unit)。注意的是,圖中的3,4,5都不是單元,它們都可以進一步被劃分,這里省略了而已;
前面我們已經(jīng)得出了三個概念:
- 組件:頁面的組成部分;
- 頁面:組件的一種。在這次設(shè)計方案里面,一個頁面對應(yīng)的就是一份配置;
-
單元:邏輯上最細粒度的組件,將不可再被拆分;
它們的關(guān)系如圖:
組件、頁面和單元
現(xiàn)在我們來分析一下這個頁面的特征。首先的是,這個頁面的布局是簡單的,可以認為是一種網(wǎng)格的布局,以從上到下,從左到右的順序逐個分布組件。整個頁面首先可以被分成1和2兩個組件,這兩個組件從上到下放好。組件2里面又被分成了3和4兩個,它們依舊是從上到下順序排列下來。最后的5,可以被認為是依次按照一行兩列一直排列下去。
其次,沒有復(fù)雜的交互。充其量也就是點點點,而后可能下面展示的內(nèi)容變了,又或者跳轉(zhuǎn)到了新的頁面。
實際上“篩選”那里并不符合簡單交互,因為篩選點了之后會彈出一個框,然后再點點點一堆。應(yīng)該算是比較復(fù)雜的交互了。
布局和樣式
布局
首先我們要考慮的就是布局和樣式的問題。前面需求特征里面已經(jīng)說過了,布局是簡單的,它可以被看成是一種網(wǎng)格:

我們將前面截圖的內(nèi)容去掉,只留下布局,那么就是圖中這個樣子。要定義這么一個東西,實際上很方便,我們只需要指定一個組件其子元素每一列放置多少個組件就可以了。因為配置里面隱含了總共多少個子元素,那么就可以計算得到行數(shù)。
還有一種比較復(fù)雜的配置解決方案,就是每一個組件,指定其寬度。假如說一行放置兩個元素,如果是平分的話,那么就是每個50%;如果不是均分,那么可以指定每個組件的寬度,可以是60%和40%,也可以是其他的分配比例。這種配置方式會帶來布局的靈活性。但是會帶來配置的復(fù)雜性。因為每一個組件至少要多一個寬度的屬性。

現(xiàn)在有很多前端的框架是支持柵格系統(tǒng)的,因此在布局方面,其實能夠省事很多。不過,此處有一個地方尤其要慎重考慮:在指定寬度布局的時候,謹慎使用固定長度。這句話的意思是,可以使用百分比的方式來指定一個組件占據(jù)的寬度,但是千萬不能直接指定它該有多寬,比如指定某個組件寬度是60px。這種方式容易變形,因為不同手機,其屏幕寬度是有區(qū)別的。
樣式
我在設(shè)計的時候,秉持了一個原則:絕不配置任何有關(guān)樣式的信息。我認為布局,如果可以避免的話,都應(yīng)該避免,只是實在避免不了而已。
我反對配置樣式的理由是:
- 配置樣式會帶來配置的急劇復(fù)雜化:一個組件的樣式,由很多控制選項,而且不同組件之間還會相互影響;
- 配置樣式導(dǎo)致樣式修改調(diào)整都十分困難:這和第一點是一而二二而一的問題,配置的復(fù)雜化會影響修改配置的任何一個地方,組件的相互影響讓你根本不敢修改;
但是,一個組件是不可能沒有樣式的。我的解決方案是,同一種類型的組件,都具有同樣的樣式。實際上,從配置上來說,基本不含有任何的樣式信息,是前端自由決定一個組件究竟長什么樣。
不過,還有一些問題要額外考慮。第一個是,如果真的有需求,比如一份配置,在兩個APP上用,兩個APP的色調(diào)不同(好吧,說的就是我司,點評APP和美團APP,一個是橘色的主色調(diào),一個是藍色的主色調(diào)),那么究竟該如何解決?這個問題可以引申為,對于一份配置,要渲染成多種風(fēng)格,該怎么搞?
這個問題還比較好解決。在配置里面指定風(fēng)格,或者說主題(Theme)。Spring實際上對此有很好的支持。也就是說,在不考慮配置組件的樣式的情況下,可以考慮一份配置作為一個整體,允許有主題的概念。主題則決定了這份配置將如何會被渲染。實際上,這已經(jīng)超出了頁面配置的范圍了。
還有一個比較棘手的問題:有兩個組件,它們除了樣式不同以外,都一樣,那么怎么辦?最為直觀的例子就是,文案一個要加粗,一個不要:

我的解決方案是,我會定義一種新的組件。這種方法十分粗暴,但是其僅適用于這一類組件不多的情況。否則會帶來組件類型膨脹的問題。
還可以考慮另外一個解決方案,這種方案是我事后完成設(shè)計之后才想出來的,未曾實踐過,不知道效果。就是,雖然我們不配置每個組件的樣式,但是我們配置每個組件的主題。比如說前面圖中的三個文案,可以指定為三種主題(normal, bold, red)。這能夠防止組件類型的膨脹,也能避免直接配置樣式帶來的問題。
我覺得,這種方法應(yīng)該算是最好的了吧。不過我還是覺得,配置不要牽涉樣式是最好的。
頁面內(nèi)容——數(shù)據(jù)
這部分要考慮的問題是:什么時候加載數(shù)據(jù)?是把數(shù)據(jù)糅合進去配置里面,或者說一份配置經(jīng)過轉(zhuǎn)變之后,也就是填充了數(shù)據(jù)之后,再交給前端,還是直接返回配置,讓前端再次發(fā)請求,以獲得數(shù)據(jù)?

對于第一種而言,很多工作被后端完成了,這在前端資源緊缺的情況下可以考慮。但是,更加好的實踐,應(yīng)該是后面一種,尤其是在涉及一些交互的時候——純粹的展示,對于兩者來說,區(qū)別并不大。
在下面交互這個部分,還會有對數(shù)據(jù)的進一步討論。
頁面交互
交互是整個配置頁面最難解決的地方。對于頁面的一次交互來說,有幾個要素:
- 目標:其實就是交互所涉及的組件;
- 觸發(fā)器:是如何觸發(fā)這一次交互的。比如說可以是點擊了某個東西,也可以是輸入了某個東西;
- 數(shù)據(jù):如,點擊一次之后顯示新的內(nèi)容,那么這個新的內(nèi)容就是數(shù)據(jù)。又或者在用戶輸入的時候?qū)崟r校驗輸入的格式,那么用戶輸入就是必然要獲取的數(shù)據(jù)
如果寫過前端的讀者,應(yīng)該很容易就看出,這個和JS的事件模型的概念是比較接近的,我只是換了一種說法而已。實際上,這也的確是參考前端事件處理的一般機制來設(shè)計的。
處理頁面交互,我其實沒有很好的方法,最根本的問題在于:如果交互涉及業(yè)務(wù)邏輯,那么就不可能通過配置來完成。
所以我采用了一種十分簡單粗暴的方法。我預(yù)定義了幾種動作,這里列舉一部分:
- 第一種動作我稱為提交。顧名思義,這個動作會將表單數(shù)據(jù)取出來一一進行校驗之后,提交給后端,并簡單提示結(jié)果;
- 第二種動作我稱為即時輸入校驗。即只要是輸入類的組件,比如輸入框,下拉框這種東西,都會在每次值發(fā)生變化的時候執(zhí)行一次前端校驗,而后在不通過的時候提示結(jié)果;
- 第三種是級聯(lián)。比如說,點擊某個地方,然后頁面展示出來的內(nèi)容就會換掉。這并不需要往后面請求數(shù)據(jù),實際上數(shù)據(jù)都取出來了,只是控制其中的部分展示與否;
這三種是我覺得比較常用的。后面又陸續(xù)添加了一些,但是大多數(shù)都圍繞那么一個核心:向后端請求數(shù)據(jù),展示某部分數(shù)據(jù)。
所以,實際上,要解決交互,最為重要的就是要解決數(shù)據(jù)訪問的問題。
頁面交互與數(shù)據(jù)訪問
頁面交互,常常要面對的一個問題是:如果交互涉及到了數(shù)據(jù),那么我該怎么取到這些數(shù)據(jù)呢?舉個例子最簡單的例子,一些范圍的輸入,比如說價格篩選范圍,要求第一個價格比第二個價格低。那么在校驗的時候,就必須要同時知道兩個輸入的內(nèi)容。

這個價格只是舉例子而已,類似的還有日期輸入。實際上良好的交互設(shè)計,或者系統(tǒng)實現(xiàn),應(yīng)該是無論用戶怎么輸入,90,或是09,或者9~9,系統(tǒng)都能給出正確的結(jié)果。
我們很容易在輸入框上綁定一個監(jiān)聽輸入的事件,也很容易獲得綁定了的那個輸入框的內(nèi)容,但是另外一個輸入框的呢?解決方案可能是,直接操作DOM樹。這種方案是能夠解決問題,只要你能夠確保擁有一個合理的組件標識符生成策略,能給予那個輸入框一個在頁面內(nèi)獨一無二的標識符。
但是還有一種更加優(yōu)雅的解決方案。這是參考當(dāng)下的一些MVVM框架的實現(xiàn)??梢栽谌志S護一個數(shù)據(jù)model。上面的例子,要校驗價格是否合理,只需要訪問這個model就可以,它已經(jīng)不需要關(guān)心這個數(shù)據(jù)究竟是怎么輸入,從哪里輸入的了。因此,擁有這個全局model之后,所有的數(shù)據(jù)訪問以及變更都是通過這個model來進行的。

這個模型能夠解決所有的跨組件通信的問題(它依然不能解決跨頁面通信問題,不過這種需求幾乎不可能出現(xiàn)在APP上)。但是它存在兩個問題沒有解決:
-
作用域隔離。因為我們只有一個全局model,所有的數(shù)據(jù)都往這里塞。我們可能會面臨這樣一個問題,這個頁面有兩個相同的字段,比如都叫totalPrice,但是它出現(xiàn)在不同的地方有不同的含義。就頁面組織而言,兩個字段可能對應(yīng)兩個屬于不同模塊的組件。全局model的困難就在于,比較難表達這種區(qū)別。一種合適的手段是采用合理的層級關(guān)系:
層級關(guān)系的model組織形式
不過,我有一個更加粗暴,我也覺得是更加好的解決方案。那就是避免出現(xiàn)這種情況。確保整個全局model里面,每一項數(shù)據(jù)都是獨一無二的。一般的應(yīng)用而言,這點是很容易做到的;
- 另外一個問題,是安全問題。數(shù)據(jù)只是放在一個model里面,自然容易出現(xiàn)非法訪問的問題。不過,在我看來,任何放在前端的數(shù)據(jù)都是不安全的數(shù)據(jù),所以,這個問題其實解決不解決,在我眼里相差不多;
回到我前面提到的,交互較多的時候,由前端分別獲取配置和數(shù)據(jù)的優(yōu)越之處就在于,單獨一次獲取數(shù)據(jù),能夠較容易構(gòu)建這樣的一個model。而如果由后端將配置和數(shù)據(jù)聚合之后,前端就需要更加復(fù)雜的解析配置的工作,以構(gòu)建這個model。
實際上,這里可以把model看做是一個中間件,只是借助于這個Model來實現(xiàn)交互中的數(shù)據(jù)傳遞。而后,通過監(jiān)聽這個Model中數(shù)據(jù)的變化來實現(xiàn)頁面刷新。這個流程做過前端開發(fā)的讀者應(yīng)該很熟悉——的確,這就是一般的MVVM框架的工作方式。

注:圖片引自http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html
所以,如果能夠借助于一些MVVM的框架,即便不是雙向綁定的框架,單向綁定的框架也能極大的簡化工作量。
交互例子
我感覺這部分還是要借助一些例子來說明我是怎么設(shè)計整個交互的。現(xiàn)在假定我們要提交數(shù)據(jù)。前面我已經(jīng)說過,所有的輸入數(shù)據(jù)都可以在model里面找到。這個表單的配置里面已經(jīng)告訴了我需要提交哪些數(shù)據(jù)(暫時忽略校驗過程),并且告訴了我要提交到哪里:

總體流程
經(jīng)過前面的分析,現(xiàn)在可以給出我們設(shè)計的前端渲染頁面的整個過程:

下面我來分析一下當(dāng)中某些過程的要點。
load module
這個過程是很重要的。我將Module定義為一些組件和預(yù)定義事件的集合。它是用來支持擴展性的一個東西。因為在開發(fā)的過程中,無法預(yù)計到會有多少種組件,也無法預(yù)計到會有何種交互。所以關(guān)鍵不在于設(shè)計好組件,而在于設(shè)計好組件接入方式。而我們自身設(shè)計好的組件,也不過是利用這種方式接入而已,切記!如果你能夠通過良好定義接口接入自己預(yù)定義好的組件,那么別人才有可能通過這個接口接入自己定義的組件。

因此,在允許別人自定義組件的情況下,就需要有能力從配置中解析出來需要用到的module,并將其加載過來。整個過程完成后,那么解析配置所需要的全部材料都已經(jīng)準備好了。
render template 和load data
渲染模板(render template)是一個可選的動作,因為后面可以在加載數(shù)據(jù)之后,render component的時候完成整個頁面渲染。首先我要解釋一下渲染模板。這個名詞其實不準確。準確的說法是渲染一切不需要數(shù)據(jù)就能完成的組件。例如,常見的頁面的頁頭,或者品牌的Logo都是直接可以渲染的,不需要經(jīng)過加載數(shù)據(jù)這么一步。因此可以先完成這一部分的渲染。這樣頁面會立刻顯示出來一部分,避免用戶長時間面對空白頁面。
在這個過程中,可以并行的是同時加載數(shù)據(jù)。例如前面截圖淘寶的頁面那樣,去加載商品數(shù)據(jù)。完成了數(shù)據(jù)加載之后,最后進行的就是render component。如果依賴于一些MVVM框架的話,這個過程大概不需要花費什么功夫。
register event
這是一個我要著重強調(diào)的步驟,注冊事件!所謂的注冊事件,就是利用已經(jīng)加載數(shù)據(jù)信息,在組件上綁定事件的過程。這個過程,要放在最后一步的原因是:某些動作是與數(shù)據(jù)相關(guān)的。比如說會員等級不同,會影響加載的組件。有些會員會出現(xiàn)額外的按鈕,或者有些會員點擊按鈕是跳轉(zhuǎn),而另外一些會員點擊按鈕卻是提示一個信息。
因此,只有在完成數(shù)據(jù)加載之后,整個頁面才是完整的。
系統(tǒng)劃分
系統(tǒng)可以如下劃分:

- model模塊:維護的則是全局model。它只應(yīng)該暴露兩個接口,一個是取數(shù)據(jù)的接口,一個是更改的接口;
- 事件模塊:它要完成整個事件的執(zhí)行。實際上,它依賴于下面的module模塊;
- module模塊:里面維護任何一個組件,任何一個事件的基本信息。頁面的渲染和事件的執(zhí)行都依賴于其中的信息;
- 通信模塊:它將負責(zé)和服務(wù)端的數(shù)據(jù)交互;
- 控制模塊:這是一個如果有必要可以進一步劃分的模塊。它將負責(zé)配置的解析,確定是否需要加載額外的模塊;在model發(fā)生變化的時候刷新頁面;頁面變化的時候?qū)?shù)據(jù)寫入等。它依賴于其余各個模塊的通力合作;
- 預(yù)定義module和第三方module:這就是事實上承擔(dān)工作的部分。我們提供了預(yù)定義的一些組件,比如復(fù)選框,下拉框等。但是也允許第三方接入自己的module。其實,這些預(yù)定義的module也是用同一種方式接入的;
額外考慮的問題
原子組件
這是一個討論拆分粒度的問題。舉個例子來說:

這個從最細粒度上來說,大概可以拆成三個部分:
- 返回的那個箭頭
- 輸入框
- 照相機圖標
然而實際上,考慮到實際的應(yīng)用場景,這三個經(jīng)常被合在一起使用,那么完全可以將它作為一個最基本的不可再拆分的原子組件了。這樣做能夠省去很多的配置。就復(fù)用性而言,也還是能夠接受了。在大多數(shù)的頁頭,都能用上。
我這里可以額外討論一下粒度的問題。組件粒度(或者是模塊粒度,業(yè)務(wù)粒度)和可用性、復(fù)用性是息息相關(guān)的。一般而言,它們的關(guān)系都是粒度越細,可用性越差,復(fù)用性越強;反之則是可用性越強,復(fù)用性越差。還有一個相關(guān)的是復(fù)雜度。粒度越細,那么組件內(nèi)部復(fù)雜性就會低,而組件之間合作的話,復(fù)雜度就會上升。

如前例子。如果拆成三個,那么輸入框是可以做成通用的輸入框組件。但是可用性會變低,因為為了配置這個頁頭,不得不指明這三個組件,以及他們的分布和一些提示文案,這也是復(fù)雜度顯著上升的表現(xiàn)。
在拆分組件的時候,要注意權(quán)衡復(fù)用性、可用性和粒度。
數(shù)據(jù)校驗
如果配置的頁面,是允許用戶輸入的,那么數(shù)據(jù)校驗就是一個很重要的點了。很不幸的是,我要解決的問題,其實就包含了大量的用戶輸入。
數(shù)據(jù)校驗要解決的一個問題是,保證后端服務(wù)器校驗邏輯和前端校驗邏輯是一致的。這是一個看起來容易,但是里面有比較多坑的問題。
首先是,因為頁面是配置的,所以校驗方式也必然是配置的。前端的校驗邏輯是從配置里面讀取的,而要保證后端校驗邏輯和前端校驗邏輯是一致的,那么豈不是后端也要去解析這份配置了?解決方案的確差不多,但不是后端讀取前端配置,而是兩者都從一個公共的地方讀取這種校驗邏輯。

注意的是,我設(shè)計的系統(tǒng)里面,除了這個可配置的前端頁面部分以外,還有一個動態(tài)解析數(shù)據(jù)后端部分與之配合。而這兩者都是一種面向元數(shù)據(jù)的模式。因此,兩者從同一個地方讀取校驗邏輯是合理的。
我可以再說一下我們定義的幾種校驗:
- 正則表達式校驗:這是最常用,也是最實用的校驗方式。幾乎任何輸入都可以用這個方式校驗,可以用于校驗手機號碼,網(wǎng)址等;
- 個數(shù)校驗:校驗復(fù)選框,圖片上傳數(shù)量等;
- 范圍和長度校驗:這兩種校驗都可以算是正則表達式的一個簡化,因為它們本來是可以用正則校驗完成的。比如價格范圍,名字長度等;
還有一種在前端實現(xiàn)起來困難重重的校驗方式,我們稱為級聯(lián)校驗。就是,要確保多個輸入數(shù)據(jù)之間滿足一定的關(guān)系。比如說你選中了某個下拉框,比如說衣服,下面它就要求你必須輸入衣服的尺寸,顏色,價格范圍。而且,如果下面的尺寸、顏色或者價格輸入了,也要確保下拉框選中了衣服。這種校驗,我們采取的方案是——不校驗,而交給后端來校驗。因為前端要配置這種校驗關(guān)系十分困難,但是交給后端就好多了。因為,無論前端是否校驗數(shù)據(jù),后端接收到數(shù)據(jù)都必須要校驗。
配置的表達
前面讀者可以看到,我們是使用json格式作為配置的表達形式的。JSON格式有很多優(yōu)點:
- 天然的樹形結(jié)構(gòu),能夠完美契合我們對布局的設(shè)計;
- 前端讀取到配置后,直接就能夠使用;
- 足夠簡單
還有一種可以供選擇的格式是xml格式。只是這種格式對前端來說并不太友好。當(dāng)然,后端配置的時候可以用XML配置,或者別的什么格式來配置,而后再經(jīng)過轉(zhuǎn)化,變成一種適合前端使用的格式。
配置存儲
配置存儲是一個挺麻煩的問題。單純的配置,是可以用文件來存儲的。但是如果要配置的數(shù)量很多的話,那么用文件來存放,會導(dǎo)致文件特別多,管理也麻煩。
一種方式是直接把配置作為一個整體存到數(shù)據(jù)庫的某個表的某個字段里面。這是一種挺不錯的解決方案,既不會太復(fù)雜,也能夠避開使用的文件的問題。
還有一種存儲方式是,直接將配置拆分成組件來進行存儲。也就是說一個組件是一行,而后維護組件之間的父子關(guān)系。這種可以帶來組件的復(fù)用,在維護配置的一致性上比較有意義。如果頁面之間有很多組件是需要共用的,那么這種存儲方式會比較合適。我們設(shè)計的系統(tǒng)第二版就是使用這種方式。存儲組件的樹形結(jié)構(gòu)使用的是路徑方式,如/component1/component2/...
大多數(shù)情況下,在Path這一個字段上建立一個索引差不多就可以了。因為組件本身是很少被修改的。
限制
- 不支持復(fù)雜布局。這種配置的頁面,不支持復(fù)雜的布局,它只能使用在布局極為有規(guī)律的地方。因為復(fù)雜的布局意味著復(fù)雜的配置,而復(fù)雜的配置——為什么不直接開發(fā)呢?
- 不支持復(fù)雜交互。
其實在不限制配置文件復(fù)雜度的情況下, 這些限制都可以被克服。這是因為,我們可以將頁面的配置看成是頁面的另外一種形式化的描述。我們常見的對頁面的描述就是HTML標簽和CSS樣式,這里不過是改為了JSON格式。前端開發(fā)的東西,不過將這種JSON配置轉(zhuǎn)化為HTML和CSS形式的描述:

注:我甚至想過一個更加復(fù)雜的解決方案,就是我們定義一套新的語言用于配置,而后再編寫一個編譯期,將這個配置語言編譯成HTML和CSS,還有JS。也就是我們認為配置一份源代碼,而HTML和CSS是編譯期輸出的結(jié)果(可以認為是編譯過程中的中間結(jié)果)。不過這個方案不具有什么可行性,太過于困難,而且收益也有點低。所以,將配置看成是另外一種形式的頁面的描述,是可配置頁面最為核心的概念了。
最后
你說的這個系統(tǒng)那么多缺點,要來何用?
我一再聲明的一個觀點是:我并不想開發(fā)一個一勞永逸的系統(tǒng)。這個系統(tǒng)也并不打算提供各種面面俱到的能力,我對它的期望是能夠解決八成問題就可以了。我一直篤信的是,如果依賴于系統(tǒng)解決剩下兩成問題所需要花費的精力,與解決這八成所花費的精力,有過之而無不及。
最直觀的是,考到80分很容易,80-90就有點難了,90-95更難。而100,那就基本上是需要上天眷顧了。
要不要開發(fā)一個可拖拽的系統(tǒng)用于配置頁面?
當(dāng)且僅當(dāng),有很多非專業(yè)人士需要配置界面的時候,才有必要開發(fā)這么一個東西。實踐證明,這種東西的學(xué)習(xí)成本和惡心程度,絕對是你不想碰的。
PC上能使用嗎?
答案是,能!實際上我第一次設(shè)計這種東西,是外調(diào)到另外一個組支援一個項目的,當(dāng)時設(shè)計的是一個PC版的可配置頁面解決方案。在PC上,要額外考慮的東西更加多,我舉一些例子:
- 布局更加復(fù)雜:APP的布局是簡單,因為屏幕寬度及其有限,可以說整個大小也有限,由此帶來了很大的布局便利。很不幸的是,這些在PC上都不再具有了;
- 元素更加復(fù)雜:在PC上,有什么iframe, modal之類的東西。也就是會有各色各樣的嵌入頁面,彈窗之類的內(nèi)容;導(dǎo)航也有千萬種,什么下拉框,面包屑……這些設(shè)計的東西真是多不勝數(shù)。如果不限制前端可以使用的元素種類,那么這個可配置頁面的解決方案,怕是要難產(chǎn)了;
- 交互復(fù)雜:如果說APP還可能受制于屏幕和交互方式,導(dǎo)致交互可以比較簡單,那么PC上就毫無顧忌了。首先就是在PC上可以輸入亂七八糟的東西——這也會帶來前端輸入校驗的痛苦,而后PC彈窗的嵌套,頁面的嵌套也是難點。最坑爹的是跨頁面通信(我就遇到了,還能比這更坑的嗎?)
講了這么多難點,我能夠提供的一點建議就是:牢牢記住頁面就是一個頂級組件。因此頁面的嵌套的可以看成是組件的嵌套,跨頁面通信可以看成是組件間通信(當(dāng)然要比一般的組件間通信困難很多,而且限制也更多)。此外就是,禁止產(chǎn)品或者設(shè)計人員自由發(fā)揮?。?!
還有就是,設(shè)計要簡單,不要復(fù)雜。如果因為少數(shù)的幾個特性會導(dǎo)致解決方案復(fù)雜化,那么還是直接開發(fā)頁面吧。
這樣配置有什么好處?
第一個好處是節(jié)省前端資源。我司前端資源緊缺,這算是設(shè)計系統(tǒng)的一個很重要的初衷了;
第二個好處是節(jié)省測試資源。因為頁面是配置的(實際上我們的數(shù)據(jù)解析也是配置的),所以后面接入新的業(yè)務(wù)的時候,基本上就是看看配置對不對,并不需要測試的介入;
第三個就是吹牛逼。是的,別人問你做了什么,可配置頁面總比一個個頁面開發(fā)過去要牛逼多了;
免責(zé)聲明
其實我是一個后端開發(fā),不過因為一些機緣巧合的東西,所以讓我設(shè)計了這么可配置頁面的解決方案,頗有一種趕鴨子上架的感覺。我只能憑借我寥寥幾個月的前端開發(fā)經(jīng)驗,設(shè)計出來了那么一套東西。雖然我在實際使用中感覺很好用,但是我同事也覺得問題多多。因此我最后要說的就是,答案僅供參考。

