三年中文在线观看免费大全_三年大片免费高清哔哩哔哩_三年在线观看免费大全哔哩_三年大全免费大片三年大片_三年在线观看免费大全_三年大片观看免费大全哔哩哔哩_三年中文在线观看免费高清第4版_三年中文免费视频大全_三年大片大全免费观看大全_三年大片在线观看哔哩哔哩_三年在线观看中文免费观看_三年成都中文在线观看免费版

我來(lái)聊聊前端應用(yòng)表現(xiàn)層抽象 - 新聞資訊 - 雲南(nán≤λ )小(xiǎo)程序開(kāi)發|雲南(nán)軟件(jiàn)開(kā♦<♠i)發|雲南(nán)網站(zhàn)建設-雲南維串信息科技有∞γ限公司

159-8711-8523

雲南(nán)網建設/小(xiǎo)程序開(kāi)發/軟件(j÷σ↓≤iàn)開(kāi)發

知(zhī)識

不(bù)管是(shì)網站(zhàn),軟件(jiàn)還(hái)是(shì)小(£♦πxiǎo)程序,都(dōu)要(yào)直接或間(jiān)接能(néng)為(w∏•÷★èi)您産生(shēng)價值,我們在追求其視(shì)覺表現(xiàn)的(de)®π$​同時(shí),更側重于功能(néng)的(de)便捷,營銷的(de)便利,運營的(de)高≈$♦×(gāo)效,讓網站(zhàn)成為(wèi)營銷工(gōng)具,讓軟件(jiàn)能($♠‌néng)切實提升企業(yè)內(nèi)部管理(lǐ)水(sh φuǐ)平和(hé)效率。優秀的(de)程序為(wèi)後期升®∑級提供便捷的(de)支持!

我來(lái)聊聊前端應用(yòng)表現(xiàn)層抽象

發表時(shí)間(jiān):2021-1-6

發布人(rén):葵宇科(kē)技(jì)

浏覽次數(shù):85

我們處于變化(huà)很(hěn)快(kuài)的(de)時(shí)φ₩代,無論是(shì)商業(yè)還(hái)是(shì)科(kē)技(jì)。一(₩φyī)家(jiā)公司看(kàn)上(shàng)去(qù)₽≈↕商業(yè)很(hěn)成功,也(yě)許前腳剛上(shàng)市(s' hì),後腳就(jiù)因為(wèi)什(shén)麽←& 而退市(shì),甚至倒閉;一(yī)項看(kàn)似高(gāo)大☆‍‍↑(dà)上(shàng)的(de)技(jì)術(shù)橫空(kōng✘∏γ)出世,各類媒體(tǐ)争先恐後地(dì)撰文(wén)介紹,熱(rè)度炒得"​σ•(de)老(lǎo)高(gāo),沒準沒多(duō)久就(jiù)出現(xiàn)了(le)​£₩§競争者、替代者。

在這(zhè)樣的(de)大(dà)環境下(xià),傳統的(de)「web 前端開(kāi)發¥≤εΩ」演變成了(le)「泛客戶端開(kāi)發」,前端開(kāi)發者從(có¥•φ¶ng)「配置工(gōng)程師(shī)」被「逼」成了(le)「軟件(ji>δ±àn)工(gōng)程師(shī)」。開(kāi)發變得(de)更複雜(zá)了(le)φε®,要(yào)處理(lǐ)的(de)問(wèn)題更多(duō)了(le),π₩從(cóng)業(yè)難度不(bù)知(zhī)提升了(le)多(duō)少(shǎo)倍↕γ✔——前端早就(jiù)不(bù)再簡單。

在衆多(duō)必須要(yào)處理(lǐ)的(de)問(wèn)題中的(d¥÷‌e)一(yī)個(gè),就(jiù)是(shì)表現(xiàn)層運行(xíng)環境的(d<®δ e)兼容問(wèn)題,像跨浏覽器(qì)和(hé)跨端、平台、技(jì)術(shù®¥)棧。注意,這(zhè)裡(lǐ)說(shuō)的(de)是(shì)「表現(xiàn)層¶σ→γ」而不(bù)是(shì)「視(shì)圖層」。

「表現(xiàn)層」與「視(shì)圖層」

「表現(xiàn)層」的(de)英文(wén)是(shì)「presentation ti'αer」或「presentation layer」,具體(tǐ)是(sπ‌→$hì)哪個(gè)取決于是(shì)物(wù)理(lǐ)上(shàng)還(hái)是(sh♦<∑ì)邏輯上(shàng)劃分(fēn);而「視(shì)圖層」的(de)英'↑β文(wén)是(shì)「view」。「表現(xiàπ>α"n)層」是(shì)「視(shì)圖層」的(de)超集≤★​ ,根據前端應用(yòng)的(de)架構設計(jì),它們既可≥¶ •(kě)以不(bù)等又(yòu)可(kě)以相(xiàng)等。$×

表現(xiàn)層

「表現(xiàn)層」這(zhè)個(gè)詞出自(zì)經典的(de≠¥ε)三層架構(或多(duō)層架構),是(shì)其中一(yī)​≥®∏個(gè)分(fēn)層。三層架構包括數(shù)據層、邏輯層和(hé)表現(xi≤>&$àn)層,一(yī)般用(yòng)在 C/S 架構中。

三層架構

為(wèi)什(shén)麽會(huì)在這(zhè)篇講前端開(kāi)發的(de)文"→₹•(wén)章(zhāng)中提到(dào)它?這(zhè)是(shì)因為 ₹ε(wèi),雖然在一(yī)些(xiē)前端應用(yòng)中用(yòng)不(∑​₩bù)到(dào),尤其是(shì)快(kuài)餐式應用(yòng),但(dàn)α‌在企業(yè)級複雜(zá)前端應用(yòng)中就(jiù)十分(fēn)需要(↑β§↓yào)一(yī)個(gè)前端的(de)「三層架構」。

視(shì)圖層

「視(shì)圖層」則來(lái)自(zì)表現(xiàn)層常用(yòng)的(¶♦de)「model-view-whatever」模式中的↕★€(de)「view」,即「視(shì)圖」。至于說(shuō)的(de)時(shí)候在•‍「視(shì)圖」後面加個(gè)「層」字合不(bù)合适,就(jiù)不(bù)在這(z✘ε≤hè)裡(lǐ)討(tǎo)論了(le),文(wén)中皆↔®使用(yòng)「視(shì)圖層」這(zhè)個(gè)詞。

運行(xíng)環境兼容

跨浏覽器(qì)

由于各浏覽器(qì)廠(chǎng)商對(duì)标準實現(xiàn)的(de)不♠"(bù)一(yī)緻以及浏覽器(qì)的(de)版本等原因,會(huγ&★ì)導緻特性支持不(bù)同、界面顯示 bug 等問(wèn)題的(de)出現(xiàn ε)。但(dàn)慶幸的(de)是(shì),他(tā)們基本是(shì)按✘¥照(zhào)标準來(lái)的(de),所以在開(k®≤<πāi)發時(shí)源碼的(de)語法幾乎沒什(shén)麽不(bù♣→≠')同。

所謂的(de)「跨浏覽器(qì)」實際上(shàng)就(jiù)是(shì¥₹≈")利用(yòng)浏覽器(qì)額外(wài)的(de)私有(yǒu)特性和(hé)技♦‍£•(jì)術(shù)或輔以 JS 對(duì)浏覽器(qì)的(de₹↓) bug 進行(xíng)「修正」與功能(néng)支持。

跨端、平台、技(jì)術(shù)棧

現(xiàn)在,絕大(dà)部分(fēn)的(de)前$>端開(kāi)發者是(shì)在做(zuò)泛客戶端開(kāi)發——開©→≈∑(kāi)發 web 應用(yòng)、客戶端應用(yòng)和(φ ☆hé)各類小(xiǎo)程序。

在做(zuò) web 應用(yòng)時(shí)需要(yào✘₩)考慮 PC 端和(hé)移動端是(shì)分(fēn)開(kāi)還(hái)是(shì)适配?¶≈'↑技(jì)術(shù)選型是(shì)用(yòng) React、Vue?還(hái)↑ε♦是(shì)用(yòng) Web Components∑£✔→?或是(shì)用(yòng)其他(tā)的(de)?做(zuò)客戶端應↑‍✔用(yòng)、各類小(xiǎo)程序時(shí)這(zhè)些(xiē)也(∞←yě)會(huì)面臨技(jì)術(shù)選型的(de)問(wèn)題 ₽。

如(rú)果公司某個(gè)業(yè)務的(de)功能(n∏'™>éng)覆蓋了(le)上(shàng)述所有(yǒu)場(chǎng)景,該如(rú)何去π♥γ♥(qù)支撐?與跨浏覽器(qì)不(bù)同的(de)是(shì),不(bù)同端、平 ±​台、技(jì)術(shù)棧的(de)源碼語法不(bù)一(yī)樣,要(yào)滿足業(yè¥ε)務需求就(jiù)得(de)各開(kāi)發一(yī)遍。然而,這(zhè)顯然成本過高(™©gāo),并且風(fēng)險也(yě)有(yǒu)些(xiē)大(dà♠÷)。

那(nà)麽,要(yào)怎麽解決這(zhè)個(gè)問(wèn)題呢(ne)? ♦從(cóng)源頭出發。根本的(de)源頭是(shì)業(yè)務場(chǎng)景,然後是£≈ (shì)産品設計(jì),但(dàn)這(zhè)些(xiē)都(dōu)不(bù)是(≤∏↔≥shì)開(kāi)發人(rén)員(yuán)可(kě)掌控的(de),幾乎無法改變。能(n∑£••éng)夠完全被開(kāi)發人(rén)員(yuán)所左右'<的(de)基本隻有(yǒu)開(kāi)發階段的(de)事(sh÷♦↕ì)情,那(nà)就(jiù)從(cóng)這(zhè≈←€↑)個(gè)階段的(de)源頭入手——源碼編寫。

若是(shì)與業(yè)務相(xiàng)關的(de)代碼隻需編寫一(yī)次就(jΩ"ε↓iù)能(néng)運行(xíng)在不(bù)同的(de)端 ‍∑、平台、技(jì)術(shù)棧上(shàng),那(nà)真是(shì)太棒了→±(le)!這(zhè)将會(huì)大(dà)大(dà)地(dì)降低(dī)<₽成本并減少(shǎo)風(fēng)險!

表現(xiàn)層的(de)抽象

為(wèi)了(le)達到(dào)跨端、平台、技(jì)術(shù)棧的(de)目的(de),需σ★≈要(yào)将表現(xiàn)層再劃分(fēn)為(wèi)抽象層、運行(xí♠&♥€ng)層和(hé)适配層。其中,抽象層是(shì)為(wèi)了(le)統一(yī)源碼的(d©σe)編寫方式,可(kě)以是(shì) DSL、配置等,它是(shì)一₩∑(yī)種協議(yì)或約定;運行(xíng)層就(jiù)是(shì)需要(yào)被「跨」的(ε♦♠de)端、平台、技(jì)術(shù)棧;适配層則是(shì)将抽象層的(de)産物(wù)轉'→‌ 換為(wèi)運行(xíng)層正常運行(xíng)所需要(yào)的(de)γ∑ε•形式。

表現(xiàn)層中可(kě)以被抽象的(de)大(dà)®±概有(yǒu)視(shì)圖結構、組件(jiàn)外(wài)觀、組件(jiàn$ )行(xíng)為(wèi)等。

視(shì)圖結構

在 web 前端開(kāi)發中,HTML 就(jiù)是(shì)一(yī"¶↑)種視(shì)圖結構的(de)抽象,描述了(le)界面中都(dōu)有(yǒu)什(shé→ ∑✔n)麽,以及它們之間(jiān)的(de)層級關系。≠¶↑λ最終的(de)顯示需要(yào)浏覽器(qì)解析 HTML 後調用(¶←$yòng)操作(zuò)系統的(de) GUI 工(gōng)具庫。

對(duì)于業(yè)務支撐來(lái)說(shuō),無論是(shì)®÷∞♣ HTML 還(hái)是(shì)其他(tā)什(shén)麽拼湊界面的(β π≥de)方式,相(xiàng)對(duì)來(lái)"♠說(shuō)比較低(dī)級(是(shì)「low ♠∑→§level」而不(bù)是(shì)「low」),視(s→​♠hì)圖單元的(de)劃分(fēn)粒度比較細,在開(kāi)發界面時(sσ≥₩ hí)就(jiù)會(huì)花(huā)費(fèi)更多(duō)的(de)時(shí)間(j•≤₹iān)。

我們需要(yào)一(yī)種能(néng)夠屏蔽一(yī)些(xiē)不(bù)必✔¶φ✘關注的(de)細節的(de)視(shì)圖結構抽象,在這(zhè)個(gè)抽象中,每個(gè)₩β視(shì)圖單元都(dōu)有(yǒu)著(zhe)其在業(yè)務上€↓(shàng)的(de)意義,而不(bù)是(shì)有(yǒu)沒有(yǒu)都(dō€Ωu)可(kě)以的(de)角色。具體(tǐ)做(zuò)法請(qǐng)看(‌&"εkàn)下(xià)文(wén)。

組件(jiàn)外(wài)觀

大(dà)部分(fēn)已存在的(de)組件(jiàn)的(de)視("↔✔shì)覺呈現(xiàn)是(shì)固定的(de),即某個(gè)組件÷‍✔γ(jiàn)的(de)尺寸、形狀、顔色、字體(tǐ)等無法被定制(zhì)。如(rú)果同樣的(dα↕e)交互隻是(shì)因為(wèi)視(shì)覺上(sγ÷≈hàng)有(yǒu)所差異就(jiù)要(yào)重新寫組×☆ €件(jiàn),或者在組件(jiàn)外(wài)部重新寫份樣式進行(xíng)覆蓋,那(nà)未"↔→免也(yě)太痛苦了(le)……

我們可(kě)以将那(nà)些(xiē)希望能(néng)夠被定≠←制(zhì)的(de)視(shì)覺呈現(xiàn)抽象φ&→✔成「主題」的(de)一(yī)部分(fēn),這(zhè)部分(fēn$¥∑φ)可(kě)以被叫做(zuò)「皮膚」。在進行(xíng)÷€定制(zhì)時(shí),分(fēn)為(wèi)線下(xià)≠↓✘和(hé)線上(shàng)兩種方式。

「線下(xià)」是(shì)指在應用(yòng)部署前的(de)開(k×§₩āi)發階段進行(xíng)處理(lǐ)。在前端構建工(gōng)具豐富的(de→β)現(xiàn)在,寫頁面樣式時(shí)已經不(bù)'♦會(huì)去(qù)直接寫 CSS,而是(shì)像 Sass 這(zhè)種可(k×✔€£ě)編程式的(de)預處理(lǐ)器(qì)。這(zhè)樣就(jiù)可(k✘ε§ě)以抽取出一(yī)些(xiē)控制(zhì)視(shì)覺呈現(x ‌σ✘iàn)的(de) Sass 變量,需要(yào)定制(zhì)時(shí)通(tōβ♣$‌ng)過在外(wài)部對(duì)變量賦值進行(xíng)覆蓋,而不(bù)÷ε→需要(yào)費(fèi)勁重寫組件(jiàn)或樣式。

「線上(shàng)」則是(shì)部署後根據運行(xíng)時(shí)數(sh→" ù)據動态改變。在皮膚定制(zhì)即時(shí)預覽和(hé)低(dī)代碼平台等φ≤§場(chǎng)景,是(shì)基本沒機(jī)會(huì)去(≥∞qù)修改 Sass 變量并走一(yī)遍構建流程的(de),即使技(jì)術(shù)δ≤上(shàng)能(néng)夠辦到(dào)。借助 CSS 自(zìπφ±₹)定義屬性(CSS 變量)的(de)力量可(kě)以較為(wèi)方≠∏便地(dì)做(zuò)到(dào)視(shì)覺呈現(xiàn)的(de)運行(xíng)時✔←♠(shí)變更。

組件(jiàn)行(xíng)為(wèi)

組件(jiàn)除了(le)外(wài)觀,其行(xíng)為(w€↕≥èi)也(yě)應當是(shì)可(kě)以定制(zhì)的(de)。看(kàn)到(dào£∞∞₩)「行(xíng)為(wèi)」這(zhè)個(gè)詞,第一(yī)反≥​β♠應就(jiù)是(shì)跟用(yòng)戶操作(zuò)相(xià✘π& ng)關的(de)事(shì)情,然而這(zhè)裡(lǐ)還(hái)包括與組件(•Ωjiàn)內(nèi)部結構相(xiàng)關的(de)。

對(duì)于組件(jiàn)的(de)外(wài)部來(↕₹lái)說(shuō),組件(jiàn)內(nèi)部就(jiù)是(shì)個×ε(gè)黑(hēi)盒子(zǐ),其自(zì)身(shēn)結構的(de✘©σ÷)組成部分(fēn)有(yǒu)的(de)可(kě)以被上(shàng)文(wén)所說(sh♥←β"uō)的(de)視(shì)圖結構所控制(zhì),有(yǒu)的(de)則無能☆ ‍<(néng)為(wèi)力:

搜索組件(jiàn)

上(shàng)圖是(shì)一(yī)個(gè)比較複雜(zá≥¥&)的(de)搜索組件(jiàn),雖然外(wài)觀​Ω和(hé)布局看(kàn)起來(lái)有(yǒu)÷©≠‌所不(bù)同,但(dàn)「它們」确實是(shì)同一∑'€(yī)個(gè)組件(jiàn)。外(wài)觀不(bβ∞÷ù)同的(de)解決方案上(shàng)面已經大(dà)體(tǐ)說(shuō)明(mín×¥g),這(zhè)類視(shì)圖結構無法控制(zhì)的(de)布局問←Ω(wèn)題,需要(yào)枚舉場(chǎng)景後在組件λ‌∞(jiàn)內(nèi)進行(xíng)支持,然後作( →♥♥zuò)為(wèi)「主題」的(de)一(yī)部分(fēn)存在。

跟用(yòng)戶操作(zuò)相(xiàng)關的(de)行§£σλ(xíng)為(wèi)有(yǒu)組件(jiàn)自(zì)身(shēn)的(de® ✔☆)交互規則及與業(yè)務邏輯的(de)結合這(zhè)兩類。

交互規則又(yòu)有(yǒu)兩種:一(yī)種是(shì)像表單是(shì)在字段值發生αε(shēng)改變時(shí)就(jiù)校(xiào)驗還(hái)是(shì)在點擊按鈕時✘ →(shí)校(xiào)驗這(zhè)樣;另一(yī)種是(shì)像字段值是(shì)在輸入框≤π☆≈的(de)值改變( input 事(shì)件(jiàn))時(shí)更新還(hái)是(shì)失焦(δε  change 事(shì)件(jiàn))時(shí)更新這(zhè)樣,≥↓或是(shì)像下(xià)拉菜單的(de)彈出層是(shì)在懸停(δ♠→ hover 事(shì)件(jiàn))時(shí)出現(xiàn)還(háiΩ©÷β)是(shì)點擊( click 事(shì)件(jiàn))時(shí)出現(xiàn)這(zhè)樣。

前者的(de)解決方式與上(shàng)面說(shuō)的(de)視(shì)圖結§Ω構無法控制(zhì)的(de)布局問(wèn)題差不 ↔&α(bù)多(duō),後者則是(shì)需要(yào)組件(jiàn)支 ↑持事(shì)件(jiàn)映射,即外(wài)部可(kě)以指定組件↕₹λ(jiàn)某些(xiē)交互的(de)觸發事(shì)件(jiàn)。當Ω<₹然,這(zhè)兩者同樣也(yě)可(kě)以作(zuò)為(wèi)「主題」的( ↓ de)一(yī)部分(fēn)。

我們在寫組件(jiàn)時(shí)有(yǒu)件(jiàn)事(shì)是(shì)需↔ ←π要(yào)極力避免卻往往難以避免——組件(jiàn)≈λ中耦合業(yè)務邏輯。組件(jiàn)決定的(de)應該隻是γ •↕(shì)外(wài)貌與交互形态,裡(lǐ)面隻有(y×∑ǒu)交互邏輯及控制(zhì)展現(xiàn)的(de)狀态,不(bù)應該牽扯到(dàδ∏&o)任何具體(tǐ)業(yè)務相(xiàng)關的(de)邏輯。隻要(yào)長(chε ∞→áng)得(de)一(yī)樣、操作(zuò)一(yī)樣,那(nà)麽就(j₹☆∞iù)應該是(shì)同一(yī)個(gè)組件(jiàn),具體(tǐ)>∏業(yè)務相(xiàng)關的(de)邏輯注入進去(qù)。

這(zhè)段十分(fēn)「個(gè)性化(huà)」的(de)業(yè♦‍∏™)務邏輯,說(shuō)白(bái)了(le)就(jiù)是(shì)響應用(yòng)♥£戶操作(zuò)的(de)變化(huà)以及業(yè)務數(s↑✔hù)據的(de)變化(huà)去(qù)更改組件(jiàn)內(nèi©•)部的(de)狀态:

{
  // 組件(jiàn)事(shì)件(jiàn)
  events: {
    // 組件(jiàn)的(de)一(yī)個(gè)點擊事(shì)件(jiàn)
    'click-a': function() {},
    // 組件(jiàn)的(de)另一(yī)個(gè)點擊事(shì)件(jià©&n)
    'click-b': function() {},
    // 組件(jiàn)的(de)一(yī)個(gè)改變事(shì)件( ∑ jiàn)
    'change-c': function() {},
  },
  // 業(yè)務數(shù)據變化(huà)的(de)回調
  watch: function( contextValue ) {},
}

運行(xíng)時(shí)會(huì)注入一(yī)個(g★σ→è)上(shàng)下(xià)文(wén)給上(sh≠∏ε​àng)述對(duì)象方法的(de) this ,組件(jiàn)還(hái)可(kě)以添加工(gōng)具方法給上(sh♣£λàng)下(xià)文(wén)。該上(shàng)下(xià)文(wén)的(de)內→β(nèi)置屬性與方法有(yǒu):

interface IDomainSpecificComponentContext {
  getStat↔Ωe(key: string): any;
  setState(key: string, value: any): void;
  setState(stateMap: { [key: string]: any }): void;
}

視(shì)圖結構描述

上(shàng)面說(shuō)了(le)我們需要(♠≤yào)一(yī)種比 HTML 之類的(de)更進一'&§(yī)步的(de)視(shì)圖結構抽象,下(xià)面就(jiù)來(§>€lái)說(shuō)說(shuō)這(zhè)部分(fēn)的(de↓₹♦♦)大(dà)體(tǐ)思路(lù)。

技(jì)術(shù)選型

在做(zuò)視(shì)圖結構抽象時(shí)最常用(yòng)到(dào)的(₩±©₽de)技(jì)術(shù)就(jiù)是(shì) XML-bγ£σ∑ased 或 XML-like 以及 JSON-based 的(☆‌¶de)某種技(jì)術(shù)。XML-base 和λ♠(hé) XML-like 的(de)技(jì)術(shù)都(dōu₽✘)是(shì)符合 XML 語法的(de),唯一(yī)的(de)區&'←×(qū)别是(shì)前者要(yào)完全符合 XML 的(de)标準規範,像 Angular π↓​™和(hé) Vue 的(de)模闆就(jiù)是(shì)後者;同樣的(de↔β​),JSON-based 的(de)技(jì)術(shù)是(shì)完全符合 JSON€≠ 的(de)标準規範的(de)技(jì)術(shù),♥¥像 JSON Schema。

自(zì)從(cóng) React 問(wèn)世以來(lái),其帶來(lái)的(de←‍​₩) XML-like 的(de) JSX 也(yě)會(huì)被用(yòng)于視(shì)圖結γ÷‍構抽象,但(dàn)基本僅限于編輯時(shí)(edit time)。一(yī)段 JSX☆✘ 代碼并不(bù)是(shì)純聲明(míng)式的(de),作(zuò)為(wèi)視β↓•(shì)圖結構描述來(lái)說(shuō)可(kě)讀(dú)性較低(dī≥"↕),解析難度較高(gāo),并且通(tōng)用(yòng)性很(hěn)低(dī©₽)。

JSON-based 的(de)技(jì)術(shù)對(duì)前端運行(xíng)時(shβ₹í)最為(wèi)友(yǒu)好(hǎo),解析成本幾乎為(wèi)零;相(xi ≥àng)反的(de),其可(kě)讀(dú)性很(hěn)低(dī),™©π JSON 結構是(shì)縱向增長(cháng)的(de),指定區(qū→$±)域內(nèi)的(de)表達力十分(fēn)受限,無法很(hěn)直觀地(dì)看€$¶(kàn)出層級關系與視(shì)圖單元的(de)屬性:

{
  "tag": "view",
  "attrs": {
    "widget": "form"
  },
  "children": [{
    "tag": "group",
    "attrs": {
      "title": "基本信息",
      "widget": "fieldset",
    },
    "children": [{
      "tag": "field",
      "attrs": {
        "name": "name",
        "label": "姓名",
        "widget": "input"
      }
    }, {
      "tag": "field",
      "attrs": {
        "name": "gender",
        "label": "性别",
        "widget": "radio"
      }
    }, {
      "tag": "field",
      "attrs": {
        "name": "age",
        "label": "年(nián)齡",
        "widget": "number"
      }
    }, {
      "tag": "field",
      "attrs": {
        "name": "birthday",
        "label": "生(shēng)日(rì)",
        "widget": "date-picker"
      }
    }]
  }, {
    "tag": "group",
    "attrs": {
      "title": "寵物(wù)",
      "widget": "fieldset",
    },
    "children": [{
      "tag": "field",
      "attrs": {
        "name": "dogs",
        "label": ":dog:",
        "widget": "select"
      }
    }, {
      "tag": "field",
      "attrs": {
        "name": "cats",
        "label": ":cat:",
        "widget": "select"
      }
    }]
  }]
}

如(rú)果一(yī)個(gè)應用(yòng)的(de)β‍設計(jì)是(shì)不(bù)需要(yào)人(ré♣₩¶♦n)工(gōng)寫視(shì)圖結構描述的(de)話(huà),可(k'§↑$ě)以考慮使用(yòng) JSON-based 的(d ₹e)技(jì)術(shù)。

像 Angular 和(hé) Vue 的(de)模闆那(nà)種 X♠π♦ML-like 的(de)技(jì)術(shù)是(shì)•≥¶•相(xiàng)對(duì)來(lái)說(shuō)最♠∑适合做(zuò)視(shì)圖結構描述的(de)——純聲明(míng)∏¶式,結構是(shì)向水(shuǐ)平與垂直兩個(gè)方向增長(chá★✘α✘ng),無論是(shì)可(kě)讀(dú)性還(hái)是(shì)表達力都(dōu)更強,→✔α解析難度适中,并且具備通(tōng)用(yòng)性。

下(xià)面的(de)模闆代碼所描述的(de)內(nèi)容與上(shà☆δεng)面那(nà)段 JSON 代碼一(yī)模一(yī)樣,深呼吸,好(hǎo)好(h®ε<ǎo)感受一(yī)下(xià)兩者之間(jiān)的(de)σ δ差異:

<view widget="form">
  <group title="基本信息" widget="fieldset">
    <field name="name" label="姓名" widget="input" />
    <field name="gender" label="性别" widget="radio" />
    <field name="age" label="年(nián)齡" widget="number" />
    <field name="birthday" label="生(shēng)日(rì)" widget="date-picker" />
  </group>
  <group title="寵物(wù)" widget="fieldset">
    <field name="dogs" label=":dog:" widget="select" />
    <field name="cats" label=":cat:" widget="select" />
  </group>
</view>

至此,視(shì)圖結構描述最終該選用(yòng)哪種技(jì)術(shù),想 φ ®必無須多(duō)言。

雞哥(gē)(小(xiǎo)雞)

設計(jì)思路(lù)

毋庸置疑,模闆的(de)語法要(yào)符合 XML 語法是(shì)前提,再γδβ在此基礎上(shàng)根據需求進行(xíng)定制(z↕≠✔≠hì)、擴展。首先要(yào)定義标簽集。所謂的(de)「标簽集」就(jiù)是(sh₽≥ì)一(yī)個(gè)元素庫,其中的(de)每個(gè)元素✔♦£•都(dōu)要(yào)具備一(yī)定語義,使其在業(yè)務上(sσ®hàng)有(yǒu)存在意義。然後是(shì)制(zhì)定描述元素的(de) sche↕ €ma 并實現(xiàn)其對(duì)應的(de)解析、校(x×↑↕iào)驗等邏輯。

元素 schema 大(dà)概是(shì)長(cháng)這€≥✔®(zhè)樣:

// 屬性值類型
type PropType = 'boolean' | 'number' | 'string' | 'regexp' | 'json';

// 屬性描述符
type PropDescriptor = {
  type: PropType | PropType[];
  required: boolean; // 是(shì)否必需
};

// 元素 schema
type ElementSchema = {
  name: string; // 元素名
  tag?: string; // 标簽名,不(bù)指定時(shí)取元素名
  props?: {
    [key: string]: PropDescriptor;
  };
  at'φ trs?: {
    resolve: (key: string, val: any) => any;
  };
  // 節點行(xíng)為(wèi),是(shì)作(zuò)為(wèi)父節點的(de)子(zǐ→$)節點還(hái)是(shì)屬性存在
  behavior?: {
    type: 'append' | 'attach';
    // 以下(xià)都(dōu)用(yòng)于 `type` 是(shì) `'₽→≥attach'` 時(shí)
    host?: string; // 宿主(屬性名)
    keyed?: boolean; // 是(shì)否為(wèi)鍵值對(duì)集合,值為( ₽wèi) `true` 且 `merge` 為(wèi) `false` 時(shí)以節點 ID€≥∞ 為(wèi)鍵
    merge?: boolean; // 當值為(wèi) `true` 時(shí)将 `reduce` 的(de)返回值與'$> `host` 指定的(de)屬性的(de)值進行(xíng)合并後重新賦值給 `>≠π₽host`
    reduce?: (node: ITemplateNode) => any; // 轉換節點信息
    restore?: (reduced: any, node?: ITemplateNode) => ITemplateNode | ​φ‌Partial<ITemplateNode>•λ;;
  };
};

可(kě)以看(kàn)到(dào) schema 中有(yǒu) props 和(hé) attrs ,它們共同組成了(le)模闆元素的(de)屬性(XML atσΩ®±tributes),區(qū)别是(shì):模闆解析後的(de)屬性如(↑↔rú)果是(shì)在 props 中定義的(de)并且滿足屬性描述符的(de) type 和(hé) required 所指定的(de)限制(zhì)條件(jiàn),會(huì)成為(wèi)模闆 γσ節點的(de) props 屬性;剩餘沒在 props 中定義的(de)則成為(wèi)模闆節點的(de) attrs 屬性,通(tōng)過 resolve 方法能(néng)夠對(duì)屬性根據自(zì)己的(de)規則進行(xíng)值的(de)轉換'€。

雖然在模闆中元素總是(shì)以嵌套的(de)形式展示出層級關系♠☆,但(dàn)一(yī)個(gè)元素并不(bù)一(yī)定就(jiù)是(shì)其父級的(d&♦φ∏e)結構,還(hái)可(kě)能(néng)是(shì) <♥<配置。因此,元素 schema 中的(de) behavior 用(yòng)于設置當前元素在模闆解析後是(shì)作(z>±¥Ωuò)為(wèi)一(yī)個(gè)節點的(de)子(zǐ)節點存在還(™←hái)是(shì)作(zuò)為(wèi)某個(gè)屬←→ 性存在。

上(shàng)述的(de)模闆設計(jì)是(shì)純視(shì)圖結構描述的(dσ↑e),并且隻對(duì)元素這(zhè)種「塊」進行(xíng)處理(lβφ★ǐ),我認為(wèi)這(zhè)樣夠用(yòng)了(le)。根據情況,可(kě)以擴展←ε‍✘為(wèi)像 Angular 和(hé) Vue 的(de)模闆那(nà)樣支持文(wé≤★∑≤n)本、插值和(hé)指令等。

如(rú)果懶癌發作(zuò)并且沒什(shén)麽特殊需求,模闆解析的(de)工(±✘gōng)作(zuò)可(kě)以交給魔改後的(de) Vue 2.6 編譯器(qì)φ•♦,再适配為(wèi)模闆節點樹(shù)。

每個(gè)模闆節點的(de)結構大(dà)緻為(wèi):

interface ITemplateNode {
  id: string;
  name: string;
  tag: string;
  props: {
    [key: string]: any;
  };
  attrs: {
    [¥Ωβ€key: string]: any;
  };
  parent: ITemplateNode | null;
  children: ITemplateNode[];
}

最後,通(tōng)過适配層将模闆節點樹(shù)轉為(wèi)運行(xíng)層的(≥↔de)組件(jiàn)樹(shù),并把渲染的(de)控制(zhìγσ€<)權也(yě)轉交給了(le)最終的(de)運行(xíng)環境。

總結

在一(yī)個(gè)複雜(zá)的(de)前端應用(y>₩§òng)中,如(rú)果不(bù)對(duì)其進行(xíng)分(fēn)層‌§,那(nà)它的(de)擴展性和(hé)可(kě)維護∞✔↕性等真的(de)會(huì)不(bù)忍直視(shì)……通(tōng)常是★λ(shì)采用(yòng)經典的(de)三層架構,從(cóng)下(xià)到(dào)上(sh₹‌àng)分(fēn)别為(wèi)數(shù)據層、邏輯層和(hé)表現(←©αxiàn)層。本文(wén)以表現(xiàn)層為(wèi)例ααΩ≤,将其再次劃分(fēn)出抽象層、運行(xíng)層和(hé)适配層這(zhè)三層,實際上(α☆↕shàng)數(shù)據層和(hé)邏輯層也(yě)可(kě)以套用(yòn±→g)這(zhè)種模式——就(jiù)像在生(shēng)日(rì)↓♦π↑蛋糕上(shàng)切上(shàng)四刀(dāo)——我稱其為(wèi)☆≥'「九宮格」模型。

「九宮格」模型

在表現(xiàn)層的(de)各種抽象中,本文(wén)著(zhe)重闡述了(le)視(s←λhì)圖結構描述的(de)技(jì)術(shù)選型與®≈±€設計(jì)思路(lù),可(kě)以看(kàn)出 XML-like 的(de)模♦"闆從(cóng)編寫到(dào)解析再到(dào)渲染這(zhè)一(yī)整條流程,與   Angular 和(hé) Vue 的(de)模闆及 HTML 大(dà)體(tǐ)上(shε♠επàng)一(yī)緻;其他(tā)抽象隻是(shì)稍微(wēi)提了(le)提"γ,以後有(yǒu)機(jī)會(huì)再展開(kāi)來(lá•ε★‌i)說(shuō)。

之前也(yě)寫過幾篇與模闆相(xiàng)關的(de)文(wén)章(zhā✘≥ng):從(cóng)提效角度與「面向組件(jiàn)」做(z®☆uò)對(duì)比的(de)《 我來(lái)聊聊面向模闆的(de♥σ∏↔)前端開(kāi)發 》;從(cóng)可(kě)定制(zhì$ φσ)性角度講的(de)《 我來(lái)聊聊配置驅動的(de)視(shì)圖開(kāi)發 》λ•δ;從(cóng)低(dī)代碼平台的(de)核心理(lǐ)念「模型驅動」出發的(de)《 ↑¶ 我來(lái)聊聊模型驅動的(de)前端開(kāi)發 》。可(kě)以說(shuō),本文(α wén)的(de)內(nèi)容是(shì)它們有(yǒu)關$↕↑±表現(xiàn)層描述的(de)「根基」。

無論一(yī)家(jiā)公司是(shì)不(bù)Ω↑÷是(shì)做(zuò)低(dī)代碼平台的(de),或者內(nèi)部有'©(yǒu)沒有(yǒu)低(dī)代碼平台,都(dōu)應該從(cóng)表現(xiàn)層'≠♥抽象出視(shì)圖結構描述,至少(shǎo)要(yào)有βε×(yǒu)如(rú)此意識。

相(xiàng)關案例查看(kàn)更多(duō)

相(xiàng)關閱讀(dú)

三年中文在线观看免费大全_三年大片免费高清哔哩哔哩_三年在线观看免费大全哔哩_三年大全免费大片三年大片_三年在线观看免费大全_三年大片观看免费大全哔哩哔哩_三年中文在线观看免费高清第4版_三年中文免费视频大全_三年大片大全免费观看大全_三年大片在线观看哔哩哔哩_三年在线观看中文免费观看_三年成都中文在线观看免费版