1. 前端可視化框架是怎樣煉成的?

        共 5944字,需瀏覽 12分鐘

         ·

        2021-03-28 10:28

        隨著移動(dòng)互聯(lián)網(wǎng)的迅猛發(fā)展和 5G 技術(shù)的普及,前端頁(yè)面需求量爆炸增長(zhǎng),用戶交互也變得越來(lái)越復(fù)雜,頁(yè)面從零開(kāi)發(fā)的成本也水漲船高。如何快速、高效地構(gòu)建前端組件乃至頁(yè)面是解放前端生產(chǎn)力的重要標(biāo)志,掌握抽象組件和頁(yè)面模型,理解前端可視化搭建思路,擺脫固有的開(kāi)發(fā)模式,提高前端開(kāi)發(fā)效率,是每位前端應(yīng)該了解的。

        從一個(gè)“栗子”說(shuō)起

        ? ? ? ? 在我們前端開(kāi)發(fā)過(guò)程中可能經(jīng)常這樣會(huì)遇到這樣的場(chǎng)景:

            (某天,產(chǎn)品經(jīng)理找到前端。)    產(chǎn)品經(jīng)理:簡(jiǎn)單開(kāi)發(fā)一個(gè)歡迎頁(yè)面,就展示下“歡迎訪問(wèn)”。    (這沒(méi)什么難度啊,代碼很好寫(xiě)了,于是前端不假思索就把代碼秀出來(lái)。)    前端:        ```        <template>            <div>                歡迎訪問(wèn)            </div>        </template>        ```    (一天之后,產(chǎn)品經(jīng)理覺(jué)得這個(gè)歡迎詞不夠具體,還想加個(gè)主語(yǔ),于是……)    產(chǎn)品經(jīng)理:那個(gè)歡迎詞簡(jiǎn)單改一下,改成“歡迎訪問(wèn)我們的網(wǎng)站”。    前端:        ```        <template>            <div>                歡迎訪問(wèn)我們的網(wǎng)站            </div>        </template>        ```     (經(jīng)過(guò)代碼提交、代碼審核、代碼合并、部署到測(cè)試環(huán)境、測(cè)試驗(yàn)證、灰度發(fā)布、產(chǎn)品驗(yàn)證、     發(fā)布上線等一系列流程,歡迎詞終于更新了……     又一天后,產(chǎn)品經(jīng)理覺(jué)得歡迎詞沒(méi)有展現(xiàn)出我們的優(yōu)勢(shì),于是加了個(gè)形容詞來(lái)描述我們的網(wǎng)站。)    產(chǎn)品經(jīng)理:那個(gè)歡迎詞還是不行,改成“歡迎訪問(wèn)我們帥氣的網(wǎng)站”。    (迫于產(chǎn)品經(jīng)理手中40米長(zhǎng)大刀的威懾,盡管心中滿是問(wèn)號(hào),前端還是修改了代碼。)    前端:        ```        <template>            <div>                歡迎訪問(wèn)我們帥氣的網(wǎng)站            </div>        </template>        ```     (又又一天后,產(chǎn)品經(jīng)理想到一個(gè)“狂拽酷炫”的形容詞,于是……)    產(chǎn)品經(jīng)理:歡迎詞再改下,改成“歡迎訪問(wèn)我們狂拽酷炫的網(wǎng)站”。    (此時(shí),前端坐不住了,想到了通過(guò)讓產(chǎn)品經(jīng)理自己維護(hù)JSON文件,在頁(yè)面中獲取JSON中title字段進(jìn)行渲染顯示)    前端:        ```        <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>        ```        (又又又一天后,產(chǎn)品經(jīng)理有了另一個(gè)想法,這次不是改歡迎詞了。)        產(chǎn)品經(jīng)理:我想再加一個(gè)選擇框,用來(lái)收集用戶信息。        (此時(shí),一陣風(fēng)吹過(guò),前端在風(fēng)中凌亂了……)


        ? ? ? ? 當(dāng)然,既然能想到通過(guò) JSON 去配置,那意味著整個(gè)組件、頁(yè)面都能配置,只需給到產(chǎn)品經(jīng)理一個(gè)可視化的界面去配置,即可生成 TA 想要的頁(yè)面,大大節(jié)省了溝通成本、提升了開(kāi)發(fā)效率。這時(shí),可視化框架應(yīng)運(yùn)而生。

        可視化框架的構(gòu)成和分工

        23672991d6493b91dd24df777449df7d.webp

        ? ? ? ? 可視化框架是怎樣的?首先我們先了解一下可視化框架的構(gòu)成和分工。開(kāi)發(fā)作為可視化框架的維護(hù)者,可以提供一個(gè)可視化的配置平臺(tái);目標(biāo)受眾,也就是可視化平臺(tái)的使用者,如上文例子中的產(chǎn)品經(jīng)理;使用者通過(guò)可視化配置平臺(tái)對(duì)頁(yè)面進(jìn)行配置,平臺(tái)會(huì)產(chǎn)出一份配置文件用來(lái)描述頁(yè)面并上傳到存儲(chǔ)空間;配置文件通過(guò)渲染引擎解析最終生成頁(yè)面。在這個(gè)構(gòu)成中,作為開(kāi)發(fā)框架的維護(hù)者,我們只需要關(guān)注可視化配置平臺(tái)和渲染引擎,當(dāng)然可視化配置平臺(tái)也只是將使用者的輸入轉(zhuǎn)化為渲染引擎能解析的配置文件并上傳,是錦上添花的一環(huán),如果還想應(yīng)用在更復(fù)雜的場(chǎng)景,還可以加上權(quán)限管理,比如 A 只能編輯 A 負(fù)責(zé)的頁(yè)面,B 只能編輯 B 復(fù)制的頁(yè)面,還可以實(shí)現(xiàn)一個(gè)工作流的流程編排,比如審核……
        ? ? ? ? 可視化框架的核心在于渲染引擎,我們?nèi)绾蔚贸鲞@個(gè)渲染引擎以及渲染引擎是如何運(yùn)作并渲染最終的頁(yè)面,是我們所關(guān)心的。如何得出渲染引擎就不得不先說(shuō)說(shuō)頁(yè)面泛化模型。

        頁(yè)面泛化模型

        0fa78c7ffe9d0fdf8052b04533a17d4f.webp

        ? ? ? ?為什么會(huì)有頁(yè)面泛化模型?因?yàn)槲覀儾煌捻?yè)面其實(shí)是通過(guò)渲染引擎解析不同的配置文件渲染出來(lái)的,因此渲染引擎需要泛化的能力。比如頁(yè)面 A 是表單填寫(xiě),那么就會(huì)要求渲染引擎能夠解析表單的配置文件;比如頁(yè)面 B 包含卡片式列表,就會(huì)要求渲染引擎能夠解析列表的配置文件。頁(yè)面泛化模型的建立,主要根據(jù)開(kāi)發(fā)者自身的經(jīng)驗(yàn)和方法建立滿足自身業(yè)務(wù)需求的模型即可。像上文案例中,如果產(chǎn)品經(jīng)理一直只要求修改歡迎詞,那案例中的那段 title 的渲染引擎就足夠滿足需求了。接下來(lái),以華為云官網(wǎng)頁(yè)面為例,拋磚引玉講講頁(yè)面泛化模型如何建立。

        12f680072d41f62df09441791676d580.webp

        ? ? ? ? 從上面截圖中我們可以看出這其實(shí)是一個(gè)從上到下的結(jié)構(gòu),可以理解為頁(yè)面是由一個(gè)個(gè)樓層構(gòu)成的,樓層可以理解為body下的一個(gè)div塊,或者是一個(gè)功能塊。比如圖中從上到下是頁(yè)頭、banner、引導(dǎo)跳轉(zhuǎn)樓層、推薦文章、技術(shù)領(lǐng)域樓層。當(dāng)然我們經(jīng)常遇到的頁(yè)面也不全都是上下結(jié)構(gòu),還有左右結(jié)構(gòu)。

        efc66639fe54ba3476adbff8d3c4bf6f.webp

        ? ? ? ? 其實(shí),像這樣左右結(jié)構(gòu)的頁(yè)面,您可以理解外層還有一個(gè)更大的容器組件包裹,整體形成一個(gè)樓層。容器組件只負(fù)責(zé)樣式,比如上圖中容器組件負(fù)責(zé)左右布局,如果您對(duì)布局還沒(méi)有概念,您可按下F12鍵查看上圖布局的代碼,您會(huì)看到其實(shí)左邊兩個(gè)模塊是被classnameedu-index-version-leftdiv包裹,右邊兩個(gè)模塊是被classnameedu-index-version-rightdiv包裹,它們依舊是從上到下的樓層。因此,頁(yè)面 = 樓層 + 容器組件

        16593d62fdcfef3bc84ec9eb1b8b308f.webp

        ? ? ? ? 再來(lái)看看樓層解構(gòu),以上圖為例,圖中主體部分是一個(gè)tab功能組件,通過(guò)查看頁(yè)面源碼,我們發(fā)現(xiàn)兩處紅色框圈出來(lái)的文本并沒(méi)有設(shè)計(jì)在tab功能組件里,而是單獨(dú)成為文本控件,這是因?yàn)檫@部分是屬于定制化的功能,并不是每個(gè)tab功能組件都有的,就抽離出來(lái)了遵循單一職責(zé)原則,藍(lán)色框是一個(gè)容器組件。再來(lái)看看tab功能組件中的卡片,卡片也是由一個(gè)一個(gè)的控件組成。因此,樓層=容器組件 +控件。

        1ef978970c4bf15bdf4b99b056d1e75a.webp

        可視化框架中的控件和常見(jiàn)的 UI 框架中的組件一樣,都具有完善且單一的職責(zé),比如表格組件,無(wú)論再怎么加功能都是在表格內(nèi)部,表格里面的功能是無(wú)法拆分出去的。但可視化框架中的控件和 UI 框架中的組件還是有區(qū)別的,主要不同點(diǎn)在于控件需要用來(lái)被編輯,因此它具有統(tǒng)一的props,所有的控件要遵循一樣的props,如視圖配置和數(shù)據(jù)源,在可視化中我們不知道頁(yè)面會(huì)用到哪些組件,因此需要統(tǒng)一去做循環(huán)渲染,不感知控件的具體屬性。

        5be6a07cf22741db4a71b1f5d390161c.webp

        ? ? ? ? 可視化框架中的容器組件本質(zhì)上也是組件,主要負(fù)責(zé)布局,分為基礎(chǔ)容器組件和功能容器組件?;A(chǔ)容器組件中左右布局一般通過(guò)柵格或者 Flex 實(shí)現(xiàn),上下布局通過(guò)正常的文本流或者定位以及控件自身間距等實(shí)現(xiàn)。功能容器組件如 tab 容器、輪播組件等。

        96287b229b27ccb154ca5a2d3aa2d1e5.webp

        ? ? ? ? 當(dāng)考慮用戶交互時(shí),事件在可視化模型中就不得不考慮??梢暬P椭械氖录枰P(guān)注交互的發(fā)起者、交互的作用者以及交互的影響方式,而不需要關(guān)注交互的種類(lèi)和交互的具體內(nèi)容。比如點(diǎn)擊了某個(gè)按鈕,步進(jìn)器的最大最小值從 1、2 變成 3、4,其實(shí)是改變了input控件的minmax屬性;比如表格篩選加了一定條件之后,顯示數(shù)據(jù)變少了,是因?yàn)橛|發(fā)了數(shù)據(jù)事件影響了表格的數(shù)據(jù)源;比如一個(gè)開(kāi)關(guān)組件,點(diǎn)擊之后控制控件的顯示和隱藏……

        4cebe14b187df55aed504c77aa823dd8.webp

        ? ? ? ? 最終,我們確定的可視化模型就是上圖中總結(jié)的點(diǎn)??梢暬?yè)面由控件 + 容器組件 + 事件組成,控件的粒度最小,是功能的最小單位;容器組件負(fù)責(zé)布局,是樣式的集合;事件響應(yīng)用戶交互傳遞控件間依賴關(guān)系。那控件、容器組件、事件是怎么結(jié)合的呢?就不得不談?wù)勪秩疽媪恕?/p>渲染引擎

        ? ? ? ? 渲染引擎本質(zhì)上也是組件,主要功能是渲染當(dāng)層組件、處理當(dāng)層組件交互關(guān)系、對(duì)當(dāng)層組件狀態(tài)進(jìn)行管理。它不關(guān)注子層組件,子層組件由子層容器的渲染引擎渲染,因?yàn)槊恳粚咏M件的配置和數(shù)據(jù)源不一樣,因此渲染結(jié)果也不相同。視圖部分示例代碼(基于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包裹,使用自定義動(dòng)態(tài)組件component的方式定義渲染引擎,帶下劃線的屬性意味著是自定義組件的內(nèi)置屬性,is決定組件渲染的類(lèi)型,如button,做到可以不感知當(dāng)層組件具體內(nèi)容渲染當(dāng)層組件;v-for循環(huán)當(dāng)前組件的屬性;v-show控制組件是否顯示,通過(guò)showState進(jìn)行狀態(tài)管理;ref建立索引,可以用來(lái)做一些高級(jí)功能,比如父層容器調(diào)用子層容器的方法;viewConfigdataSource就是上文中提到的控件中所必需的;@valueChange是組件提交的統(tǒng)一事件。

        17ff76d5e80fd085fda5262bbba5efeb.webp

        ? ? ? ? 父層容器和子層容器本質(zhì)都是渲染引擎,只是樣式不同。比如說(shuō)一個(gè)左右布局的容器組件,相當(dāng)于在視圖中v-for循環(huán)的地方綁定一個(gè)class如柵格布局或者flex布局的樣式,如果是柵格布局的話,用戶就要先定義type是柵格組件,然后配置viewConfiggrid屬性之類(lèi)的,如果是flex布局,定義的type就是flex組件,對(duì)齊方式如指定為space-between之類(lèi)的。上文中示例代碼就是一個(gè)正常的從上到下的布局。

        25baac80e93771efa8f1d1d77e89977d.webp

        ? ? ? ? 首先外層傳遞兩個(gè)關(guān)鍵的參數(shù)--viewConfigdataSource,當(dāng)層容器就會(huì)進(jìn)行配置解析和配置分發(fā)。配置解析主要包含屬性映射和生成事件,屬性映射比如控件本身需要title屬性,而配置文件中可能是叫label屬性,這時(shí)我們要將label轉(zhuǎn)換成title,只不過(guò)轉(zhuǎn)換邏輯不包含在渲染引擎中,只是調(diào)用外部封裝好的方法;生成事件則是根據(jù)配置生成預(yù)設(shè)事件并掛載。在配置分發(fā)之前,會(huì)先將解析好的配置進(jìn)行初始化父層狀態(tài)并存放在父層,主要考慮到viewConfig和dataSource不是同步賦值,需要等待都就緒了才進(jìn)行分發(fā)。

        b13206fc2aedf6db5c2495cbe6d44d6b.webp

        ? ? ? ? 在介紹控件的時(shí)候,提到每個(gè)控件都要提交,因?yàn)槊總€(gè)控件都不能成為其他控件的一個(gè)origin。比如Tip組件,雖然本身可能沒(méi)有交互,但可能成為別的控件的依賴項(xiàng),子層可能需要獲取內(nèi)容,子層容器的提交會(huì)被收集在父層容器的valueWatch中,在子層容器提交以后,如果狀態(tài)變化的話,那父層容器就會(huì)根據(jù)functionList去循環(huán)執(zhí)行的事件;如果是展示類(lèi)事件,就會(huì)更新父層的showState控制顯示或隱藏,如果是數(shù)據(jù)類(lèi)事件,則會(huì)改變viewConfigdataSource,對(duì)目標(biāo)進(jìn)行一個(gè)重新賦值??偟脕?lái)說(shuō)渲染引擎流程就包含以上四個(gè)步驟:配置解析、配置分發(fā)、收集提交、發(fā)起事件。

        總結(jié)

        ? ? ? ? 為了減少頁(yè)面開(kāi)發(fā)代碼量,提升代碼復(fù)用度,我們期望頁(yè)面能進(jìn)行可視化編輯;為了得出一個(gè)通過(guò)的可視化框架,我們對(duì)頁(yè)面進(jìn)行了可視化建模分析,得出幾乎所有的頁(yè)面都可以由控件和容器組件構(gòu)成,通過(guò)泛化的事件處理用戶交互和組件間的級(jí)聯(lián)關(guān)系;根據(jù)建模的結(jié)果建立了渲染引擎,支撐起整個(gè)流程,最終實(shí)現(xiàn)可視化。


        本文整理自華為云社區(qū)內(nèi)容共創(chuàng)活動(dòng)第二期之【線上直播】2.0倍起步?高效完成前端頁(yè)面。
        查看活動(dòng)詳情:https://bbs.huaweicloud.com/forum/thread-111494-1-1.html


        瀏覽 103
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 国产精品久久久久久久久小说 | 91午夜福利视频 | 亚洲中文字幕网 | 欧美青青视频手机在线 | 国产人妻人伦精品一区二区网站 |