1. 程式人生 > >我終於知道公司前端為啥不加班了…

我終於知道公司前端為啥不加班了…

摘要:如何快速、高效地構建前端元件乃至頁面是解放前端生產力的重要標誌,掌握抽象元件和頁面模型,理解前端視覺化搭建思路,擺脫固有的開發模式,提高前端開發效率,是每位前端應該瞭解的。

本文分享自華為雲社群《【雲駐共創】前端視覺化框架是怎樣煉成的?》,原文作者:華為雲EI專家胡琦。

隨著移動網際網路的迅猛發展和 5G 技術的普及,前端頁面需求量爆炸增長,使用者互動也變得越來越複雜,頁面從零開發的成本也水漲船高。如何快速、高效地構建前端元件乃至頁面是解放前端生產力的重要標誌,掌握抽象元件和頁面模型,理解前端視覺化搭建思路,擺脫固有的開發模式,提高前端開發效率,是每位前端應該瞭解的。

從一個“栗子”說起

在我們前端開發過程中可能經常這樣會遇到這樣的場景:

(某天,產品經理找到前端。)
    產品經理:簡單開發一個歡迎頁面,就展示下“歡迎訪問”。
    (這沒什麼難度啊,程式碼很好寫了,於是前端不假思索就把程式碼秀出來。)
    前端:
        ```
        <template>
            <div>
                歡迎訪問
            </div>
        </template>
        ```
    (一天之後,產品經理覺得這個歡迎詞不夠具體,還想加個主語,於是……)
    產品經理:那個歡迎詞簡單改一下,改成“歡迎訪問我們的網站”。
    前端:
        ```
        <template>
            <div>
                歡迎訪問我們的網站
            </div>
        </template>
        ```
     (經過程式碼提交、程式碼稽核、程式碼合併、部署到測試環境、測試驗證、灰度釋出、產品驗證、
     釋出上線等一系列流程,歡迎詞終於更新了……
     又一天後,產品經理覺得歡迎詞沒有展現出我們的優勢,於是加了個形容詞來描述我們的網站。)
    產品經理:那個歡迎詞還是不行,改成“歡迎訪問我們帥氣的網站”。
    (迫於產品經理手中40米長大刀的威懾,儘管心中滿是問號,前端還是修改了程式碼。)
    前端:
        ```
        <template>
            <div>
                歡迎訪問我們帥氣的網站
            </div>
        </template>
        ```
     (又又一天後,產品經理想到一個“狂拽酷炫”的形容詞,於是……)
    產品經理:歡迎詞再改下,改成“歡迎訪問我們狂拽酷炫的網站”。
    (此時,前端坐不住了,想到了通過讓產品經理自己維護JSON檔案,在頁面中獲取JSON中title欄位進行渲染顯示)
    前端:
        ```
        <template>
        <div>
            {{title}}
        </div>
        </template>
        <script>
        import axios from "axios";
        export default {
            data() {
                return {
                    title: ''
                }
            },
            created() {
                this.queryTitle()
            },
            methods: {
                queryTitle() {
                    axios.get('JSON檔案所在路徑').then(res=>{
                        if(res && res.status === 200) {
                            this.title = res.data.title
                        }
                    })
                }
            }
        }
        </script>
        ```
        (又又又一天後,產品經理有了另一個想法,這次不是改歡迎詞了。)
        產品經理:我想再加一個選擇框,用來收集使用者資訊。
        (此時,一陣風吹過,前端在風中凌亂了……)

當然,既然能想到通過 JSON 去配置,那意味著整個元件、頁面都能配置,只需給到產品經理一個視覺化的介面去配置,即可生成 TA 想要的頁面,大大節省了溝通成本、提升了開發效率。這時,視覺化框架應運而生。

視覺化框架的構成和分工

視覺化框架是怎樣的?首先我們先了解一下視覺化框架的構成和分工。開發作為視覺化框架的維護者,可以提供一個視覺化的配置平臺;目標受眾,也就是視覺化平臺的使用者,如上文例子中的產品經理;使用者通過視覺化配置平臺對頁面進行配置,平臺會產出一份配置檔案用來描述頁面並上傳到儲存空間;配置檔案通過渲染引擎解析最終生成頁面。在這個構成中,作為開發框架的維護者,我們只需要關注視覺化配置平臺和渲染引擎,當然視覺化配置平臺也只是將使用者的輸入轉化為渲染引擎能解析的配置檔案並上傳,是錦上添花的一環,如果還想應用在更復雜的場景,還可以加上許可權管理,比如 A 只能編輯 A 負責的頁面,B 只能編輯 B 複製的頁面,還可以實現一個工作流的流程編排,比如稽核……

視覺化框架的核心在於渲染引擎,我們如何得出這個渲染引擎以及渲染引擎是如何運作並渲染最終的頁面,是我們所關心的。如何得出渲染引擎就不得不先說說頁面泛化模型。

頁面泛化模型

為什麼會有頁面泛化模型?因為我們不同的頁面其實是通過渲染引擎解析不同的配置檔案渲染出來的,因此渲染引擎需要泛化的能力。比如頁面 A 是表單填寫,那麼就會要求渲染引擎能夠解析表單的配置檔案;比如頁面 B 包含卡片式列表,就會要求渲染引擎能夠解析列表的配置檔案。頁面泛化模型的建立,主要根據開發者自身的經驗和方法建立滿足自身業務需求的模型即可。像上文案例中,如果產品經理一直只要求修改歡迎詞,那案例中的那段 title 的渲染引擎就足夠滿足需求了。接下來,以華為雲官網頁面為例,拋磚引玉講講頁面泛化模型如何建立。

從上面截圖中我們可以看出這其實是一個從上到下的結構,可以理解為頁面是由一個個樓層構成的,樓層可以理解為body下的一個div塊,或者是一個功能塊。比如圖中從上到下是頁頭、banner、引導跳轉樓層、推薦文章、技術領域樓層。當然我們經常遇到的頁面也不全都是上下結構,還有左右結構。

其實,像這樣左右結構的頁面,您可以理解外層還有一個更大的容器元件包裹,整體形成一個樓層。容器元件只負責樣式,比如上圖中容器元件負責左右佈局,如果您對佈局還沒有概念,您可按下F12鍵檢視上圖佈局的程式碼,您會看到其實左邊兩個模組是被classname為edu-index-version-left的div包裹,右邊兩個模組是被classname為edu-index-version-right的div包裹,它們依舊是從上到下的樓層。因此,頁面 = 樓層 + 容器元件。

再來看看樓層解構,以上圖為例,圖中主體部分是一個tab功能元件,通過檢視頁面原始碼,我們發現兩處紅色框圈出來的文字並沒有設計在tab功能元件裡,而是單獨成為文字控制元件,這是因為這部分是屬於定製化的功能,並不是每個tab功能元件都有的,就抽離出來了遵循單一職責原則,藍色框是一個容器元件。再來看看tab功能元件中的卡片,卡片也是由一個一個的控制元件組成。因此,樓層=容器元件 +控制元件。

視覺化框架中的控制元件和常見的 UI 框架中的元件一樣,都具有完善且單一的職責,比如表格元件,無論再怎麼加功能都是在表格內部,表格裡面的功能是無法拆分出去的。但視覺化框架中的控制元件和 UI 框架中的元件還是有區別的,主要不同點在於控制元件需要用來被編輯,因此它具有統一的props,所有的控制元件要遵循一樣的props,如檢視配置和資料來源,在視覺化中我們不知道頁面會用到哪些元件,因此需要統一去做迴圈渲染,不感知控制元件的具體屬性。

視覺化框架中的容器元件本質上也是元件,主要負責佈局,分為基礎容器元件和功能容器元件。基礎容器元件中左右佈局一般通過柵格或者 Flex 實現,上下佈局通過正常的文字流或者定位以及控制元件自身間距等實現。功能容器元件如 tab 容器、輪播元件等。

當考慮使用者互動時,事件在視覺化模型中就不得不考慮。視覺化模型中的事件需要關注互動的發起者、互動的作用者以及互動的影響方式,而不需要關注互動的種類和互動的具體內容。比如點選了某個按鈕,步進器的最大最小值從 1、2 變成 3、4,其實是改變了input控制元件的min和max屬性;比如表格篩選加了一定條件之後,顯示資料變少了,是因為觸發了資料事件影響了表格的資料來源;比如一個開關元件,點選之後控制控制元件的顯示和隱藏……

最終,我們確定的視覺化模型就是上圖中總結的點。視覺化頁面由控制元件 + 容器元件 + 事件組成,控制元件的粒度最小,是功能的最小單位;容器元件負責佈局,是樣式的集合;事件響應使用者互動傳遞控制元件間依賴關係。那控制元件、容器元件、事件是怎麼結合的呢?就不得不談談渲染引擎了。

渲染引擎

渲染引擎本質上也是元件,主要功能是渲染當層元件、處理當層元件互動關係、對當層元件狀態進行管理。它不關注子層元件,子層元件由子層容器的渲染引擎渲染,因為每一層元件的配置和資料來源不一樣,因此渲染結果也不相同。檢視部分示例程式碼(基於Vue.js)如下:

<template>
    <div :class="clsPrefix">
        <component
            :is="component._type"
            v-for="component in viewConfig.components"
            v-show="showState[component._id]"
            :ref="component._id"
            :key="component._id"
            :viewConfig="component"
            :dataSource="dataSource[component._id]"
            @valueChange="valueChangeHandler($event, component._id)"
        />
    </div>
</template>

最外層是由div包裹,使用自定義動態元件component的方式定義渲染引擎,帶下劃線的屬性意味著是自定義元件的內建屬性,is決定元件渲染的型別,如button,做到可以不感知當層元件具體內容渲染當層元件;v-for迴圈當前元件的屬性;v-show控制組件是否顯示,通過showState進行狀態管理;ref建立索引,可以用來做一些高階功能,比如父層容器呼叫子層容器的方法;viewConfig和dataSource就是上文中提到的控制元件中所必需的;@valueChange是元件提交的統一事件。

父層容器和子層容器本質都是渲染引擎,只是樣式不同。比如說一個左右佈局的容器元件,相當於在檢視中v-for迴圈的地方繫結一個class如柵格佈局或者flex佈局的樣式,如果是柵格佈局的話,使用者就要先定義type是柵格元件,然後配置viewConfig中grid屬性之類的,如果是flex佈局,定義的type就是flex元件,對齊方式如指定為space-between之類的。上文中示例程式碼就是一個正常的從上到下的佈局。

首先外層傳遞兩個關鍵的引數--viewConfig和dataSource,當層容器就會進行配置解析和配置分發。配置解析主要包含屬性對映和生成事件,屬性對映比如控制元件本身需要title屬性,而配置檔案中可能是叫label屬性,這時我們要將label轉換成title,只不過轉換邏輯不包含在渲染引擎中,只是呼叫外部封裝好的方法;生成事件則是根據配置生成預設事件並掛載。在配置分發之前,會先將解析好的配置進行初始化父層狀態並存放在父層,主要考慮到viewConfig和dataSource不是同步賦值,需要等待都就緒了才進行分發。

在介紹控制元件的時候,提到每個控制元件都要提交,因為每個控制元件都不能成為其他控制元件的一個origin。比如Tip元件,雖然本身可能沒有互動,但可能成為別的控制元件的依賴項,子層可能需要獲取內容,子層容器的提交會被收集在父層容器的valueWatch中,在子層容器提交以後,如果狀態變化的話,那父層容器就會根據functionList去迴圈執行的事件;如果是展示類事件,就會更新父層的showState控制顯示或隱藏,如果是資料類事件,則會改變viewConfig和dataSource,對目標進行一個重新賦值。 總得來說渲染引擎流程就包含以上四個步驟:配置解析、配置分發、收集提交、發起事件。

總結

為了減少頁面開發程式碼量,提升程式碼複用度,我們期望頁面能進行視覺化編輯;為了得出一個通過的視覺化框架,我們對頁面進行了視覺化建模分析,得出幾乎所有的頁面都可以由控制元件和容器元件構成,通過泛化的事件處理使用者互動和元件間的級聯關係;根據建模的結果建立了渲染引擎,支撐起整個流程,最終實現視覺化。

本文整理自華為雲社群內容共創活動第二期之【線上直播】2.0倍起步?高效完成前端頁面。

檢視活動詳情:https://bbs.huaweicloud.com/forum/thread-111494-1-1.html

 

點選關注,第一時間瞭解華為雲新鮮技術~