新聞中心
1.為什么要實施前端組件化?

目前創(chuàng)新互聯(lián)已為1000+的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬空間、網(wǎng)站托管、服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計、巧家網(wǎng)站維護等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
在項目開發(fā)中,頁面和功能大都拆分為多文件來實現(xiàn),多文件管理逐漸暴露出以下問題:
- 相似的業(yè)務(wù)代碼無法復(fù)用:X同事實現(xiàn)了一遍A頁面,Y同事要實現(xiàn)一個和A頁面類似的B頁面,發(fā)現(xiàn)X同事的代碼無法有效復(fù)用,只好重新再寫一遍。
- 多人重復(fù)實現(xiàn)同一功能:X同事完成了A功能,Y同事開發(fā)時要做同樣的功能,但是并不知道X同事已經(jīng)實現(xiàn)了,又重新寫了一遍。
隨著項目的不斷迭代,以上問題便會導(dǎo)致:
- 代碼體積不斷增加,冗余越來越大;
- 業(yè)務(wù)邏輯復(fù)雜度不斷增加,邏輯的可擴展性、可維護性、健壯性越來越差;
而產(chǎn)生以上問題的原因主要體現(xiàn)在:
- 相似代碼重復(fù)開發(fā);
- 復(fù)用功能代碼的方式是簡單粗暴的復(fù)制粘貼;
- 團隊內(nèi)協(xié)作開發(fā)導(dǎo)致代碼耦合度高,后期維護難;
隨著項目的迭代,從長期維護的穩(wěn)定性和可操作性方面來看,大多數(shù)人都想過無數(shù)次重構(gòu)和優(yōu)化,卻總是不敢輕易“動”。所以在前端項目工程化的前提下,引入了前端組件化,從功能模塊的復(fù)用及多人協(xié)作層面進行解耦。
2.組件化:前端解耦的有效利器
2.1 什么是前端組件化?
前端的組件化,其實是對項目進行自上而下的拆分,把通用的、可復(fù)用的功能中的模型(Model)、視圖(View)和視圖模型(ViewModel)以黑盒的形式封裝到一個組件中,然后暴露一些開箱即用的函數(shù)和屬性配置供外部組件調(diào)用,實現(xiàn)與業(yè)務(wù)邏輯的解耦,來達到代碼間的高內(nèi)聚、低耦合,實現(xiàn)功能模塊的可配置、可復(fù)用、可擴展。除此之外,還可以再由這些組件組合更復(fù)雜的組件、頁面。
上面提到了要對項目進行拆分,那經(jīng)常聽到的模塊化與組件化都涉及了對項目的模塊拆分,指的是一回事嗎?
組件化≠模塊化。模塊化是從文件層面上,對代碼或資源進行拆分;而組件化是從設(shè)計層面上,對用戶界面進行拆分。前端組件化更偏向UI層面,更多把邏輯放到頁面中,使得UI元素復(fù)用性更高。
換句話說,頁面上所有的東西都可以是組件,可以把頁面看作大型業(yè)務(wù)組件,它又能拆分為多個中型業(yè)務(wù)組件,然后可以再拆分成多個復(fù)合組件,復(fù)合組件再拆成多個基礎(chǔ)組件,直到拆成Dom元素為止。實際項目開發(fā)中,只需要應(yīng)用這些組件,像搭積木一樣完成頁面的搭建就可以了。
圖1 頁面與組件間的關(guān)系
2.2 組件化思維
組件化思維的精髓是獨立、完整、自由組合。以此為目標,盡可能把設(shè)計和開發(fā)中的元素獨立化,使其具備完整的功能,通過自由組合來構(gòu)成整個頁面/產(chǎn)品。
2.3 組件分類
一般常見的組件可以劃分為這四種:基礎(chǔ)組件、業(yè)務(wù)組件、區(qū)塊、頁面。
圖2 組件分類與關(guān)系圖
基礎(chǔ)組件:不包含業(yè)務(wù),具備獨立具體的功能,比如button、input、select等組件。項目中不需要關(guān)心也無法修改組件內(nèi)部的代碼,通過組件定義的props配置來實現(xiàn)不同的功能;
業(yè)務(wù)組件:由基礎(chǔ)組件組合而成,含有業(yè)務(wù)邏輯的組件;
區(qū)塊:由基礎(chǔ)組件和業(yè)務(wù)組件組合而成;項目中對于區(qū)塊代碼可以進行任何改動,這是區(qū)塊和業(yè)務(wù)組件的最大區(qū)別;
頁面:呈現(xiàn)給用戶的頁面,也可以看作是業(yè)務(wù)組件。
2.4 組件化的特點
網(wǎng)上對于組件化并沒有一個明確的定義,但是在提到組件化的時候都會提到高內(nèi)聚、低耦合。也就是希望每個組件對內(nèi)做到各個元素緊密結(jié)合,互相依賴;對外和其他組件的聯(lián)系最少且接口簡單,可復(fù)用可組合。組件化的意義在于提效,希望可以交付可用的、直觀的、可組合的業(yè)務(wù)形態(tài)。
如果項目實現(xiàn)了組件化,那么寫代碼就具有了更高的靈活性,可擴展性和可維護性。
圖3 組件化特點
2.5 組件化開發(fā)后的新面貌
組件化以后,一個頁面可能是這個樣子的:
圖4 頁面與組件的構(gòu)成
項目可能是這個樣子的:項目內(nèi)部對應(yīng)多個頁面,頁面內(nèi)部對應(yīng)多個組件,組件內(nèi)部又可能對應(yīng)了多個不同的庫。
圖5 項目、頁面與組件的關(guān)系分布
3.實際業(yè)務(wù)開發(fā):具體問題具體分析
3.1 組件設(shè)計原則
無論是基礎(chǔ)組件還是業(yè)務(wù)組件,在設(shè)計時都應(yīng)遵循一定的原則:
單一性:一個組件只專注做一件事,且把這件事做好。一個功能如果可以拆分為多個功能點,就將每個功能點封裝為一個組件,但并不是組件的顆粒度越小越好,只要將一個組件內(nèi)的功能和邏輯控制好即可。
可配置:明確組件的輸入和輸出分別是什么。比如組件內(nèi)的文本、按鈕、字體顏色、按鈕位置等,都是可配置的,最基本的配置方式就是通過屬性想組件傳遞配置的值。
粒度適中:劃分的粒度大小要根據(jù)實際情況權(quán)衡,太小會提升維護成本,太大又不夠靈活。組件的抽象粒度并不是越細越好,拆分是為了分層、復(fù)用,在基本原則不變的前提下,我們更應(yīng)該關(guān)注如何適配不同的業(yè)務(wù)場景和需求,合適才是最重要的。
3.2 如何在項目中實施前端組件化?
實際項目中基礎(chǔ)組件并不能滿足我們的業(yè)務(wù)需求,往往會包含大量重復(fù)的業(yè)務(wù)場景。而這些業(yè)務(wù)場景又大同小異,有些是具有一定業(yè)務(wù)邏輯的組件,另一些是由基礎(chǔ)組件和業(yè)務(wù)組件組合成的模塊等。
|
思考 | |
|
① |
那么這些重復(fù)的工作能否用機器來解決? |
|
② |
如何更好的復(fù)用這些業(yè)務(wù)組件來降低開發(fā)成本呢? |
|
③ |
能否在前端資源緊缺的情況下,直接使用現(xiàn)有工具搭建出想要的頁面和項目? |
帶著這些問題,中臺技術(shù)部的前端團隊開發(fā)了Elsa插件,提供項目模板以及高質(zhì)量的業(yè)務(wù)組件來解決這些問題。之所以使用插件,就是在避免現(xiàn)有可視化工具痛點的基礎(chǔ)上,讓開發(fā)更加高效輕松。Elsa把現(xiàn)有項目中可共用的業(yè)務(wù)組件都發(fā)布為一個jnpm包,以組件庫列表呈現(xiàn)給用戶,方便開發(fā)人員安裝使用,還可下載對應(yīng)組件后在其基礎(chǔ)上進行二次開發(fā),再發(fā)布jnpm,來滿足更加多樣的業(yè)務(wù)場景。同時,還提供了自定義組件,賦予用戶開發(fā)的自由度,發(fā)布自己業(yè)務(wù)組件到j(luò)npm后同樣呈現(xiàn)在列表,從而豐富和沉淀出更多的業(yè)務(wù)組件。
圖6 Elsa-組件庫列表頁面
業(yè)務(wù)組件的開發(fā)離不開基礎(chǔ)組件,Elsa也提供了可視化拼裝表單功能,提供表單頁面的基礎(chǔ)組件元素,通過拖拽輕松完成表單頁面的搭建。
圖7 Elsa-拼裝組件頁面
并且針對不同的業(yè)務(wù)場景和頁面模式,該插件還提供了多版項目模板。開發(fā)人員可以直接使用現(xiàn)有項目模板進行開發(fā),極大地降低了項目研發(fā)和維護的成本。
圖8 Elsa-創(chuàng)建應(yīng)用頁面
關(guān)于Elsa中目前沉淀出的業(yè)務(wù)組件是從哪里來?又是如何從項目拆分、設(shè)計的?目前Elsa列表中提供的業(yè)務(wù)組件是從產(chǎn)品中心中抽取封裝發(fā)布的,在重構(gòu)中提供了極大的便利,團隊別的同事可以很方便的下載使用。所以下文組件拆分就以產(chǎn)品中心為例說明。
3.3 組件拆分
面對項目中一個功能幾百行上千行,都堆積在一個js文件中,尤其在剛接手別人項目得時候遇到這種情形會極其崩潰。這個現(xiàn)象就像蓋房子時,地基不穩(wěn),還在上面一直摞磚,這樣的房子試問有人敢住嗎?那同樣的,這樣的代碼運行起來隨時都可能會出現(xiàn)意想不到的問題,可能下一秒出現(xiàn)問題,可能增加了某個功能后出現(xiàn)問題......OMG,項目要上線,BUG改不完,問題還沒有定位到,怕是要完蛋了......
目前業(yè)內(nèi)對于組件拆分也沒有統(tǒng)一的標準。因為每個人對組件化的理解不同,拆分邊界、程度都要結(jié)合具體的業(yè)務(wù)場景來思考。拆分思路也可以借鑒Vue官網(wǎng)的一個圖來說明:
圖9 vue中組件系統(tǒng)的劃分
中臺技術(shù)部的前端團隊在拆分組件時,除按照布局和人員分工拆分之外,主要從這兩個角度來考慮的:
項目內(nèi)是否可復(fù)用:即同頁面或者多頁面都用到的功能模塊(比如產(chǎn)品中心的表格、分頁、日志組件)。
頁面內(nèi)出現(xiàn)頻率:如果某部分出現(xiàn)頻率很高,但總有一部分差異,考慮插槽方式封裝組件。
重構(gòu)項目前先做了項目整體業(yè)務(wù)邏輯和代碼架構(gòu)的梳理,制定出組件化方案。對比以下幾個頁面:
圖10 產(chǎn)品中心頁面A
圖11 產(chǎn)品中心頁面B
圖12 產(chǎn)品中心頁面C
現(xiàn)象描述
相同點:從頁面結(jié)構(gòu)來看,自上而下都是由過濾框條件、操作按鈕、表格、分頁模塊組成。
不同點:過濾條件不同,操作按鈕不同,表格列不同。
拆分思路
將每個頁面都劃分成過濾條件組件、表格組件和分頁組件來實現(xiàn)組件間的獨立、再組合完成復(fù)用。
封裝設(shè)計
- 過濾條件:關(guān)于過濾條件組件,如果差異不大,都是由固定屬性集合中的內(nèi)容來過濾,可以v-if控制顯示。如果各頁面的過濾條件基本不同,按照最小粒度劃分那就是select、input類型,那就以最小粒度的視角來拆分,實現(xiàn)更高程度的復(fù)用。根據(jù)業(yè)務(wù)場景和頁面來看,如果都涉及到了產(chǎn)品分類,產(chǎn)品線等同樣的內(nèi)容,就不需要更小粒度的劃分了,可以將數(shù)據(jù)直接綁定上去封裝在組件內(nèi)部。
- 表格:其實哪個位置不同,哪就可配置。很明顯,表格組件應(yīng)該包含兩部分,由操作按鈕+表格組成。既然頁面都有操作按鈕,但總有一些不同,參考上面的原則2來用slot插槽實現(xiàn)。表格列和對應(yīng)的數(shù)據(jù)通過傳參綁定,表格列中的操作按鈕同樣也采取slot插槽根據(jù)頁面差異自定義。
- 分頁:分頁組件UI是統(tǒng)一的,那么它只是根據(jù)數(shù)據(jù)來顯示對應(yīng)的內(nèi)容,只要綁定數(shù)據(jù)即可。
業(yè)務(wù)發(fā)展前期,可能這樣抽取的組件通用性很強了。當(dāng)日積月累業(yè)務(wù)中增加了新的需求,同一項目中的不同頁面中類似的模塊又有別的差異無法用現(xiàn)有的組件邏輯來滿足,需要不斷新增參數(shù)。此時組件內(nèi)部出現(xiàn)了大量的判斷邏輯。盡管組件的通用性再好,可以應(yīng)對各種頁面的邏輯,但此時組件本身已經(jīng)變得更難以維護。這個時候就應(yīng)該思考:抽離組件應(yīng)該做業(yè)務(wù)層和視圖層的分離,視圖層負責(zé)頁面的樣式和交互,業(yè)務(wù)層處理業(yè)務(wù)邏輯(接口調(diào)用、數(shù)據(jù)結(jié)構(gòu)調(diào)整等)。這種情形在常見的新增、編輯頁面,就可以避免組件中的耦合判斷,共用一個視圖,并在各自的業(yè)務(wù)層實現(xiàn)不同的業(yè)務(wù)邏輯。
table組件主要部分:
ref="multipleTable"
v-loading="loading"
:stripe="ifStripe"
:border="border"
:height="`calc(100% - ${pageHeight}px)`"
:max-height="maxHeight"
:style="{ width: '100%' }"
:data="dataSource"
v-bind="options"
v-on="tableEvents"
@selection-change="handleSelectionChange"
>
v-if="options && options.selection && (!options.isShow || options.isShow())"
type="selection"
width="55"
:align="alignDirestion"
>
v-if="operates && operates.length > 0"
:fixed="operatesDir"
label="操作"
width="200"
v-bind="options && options.props"
:align="alignDirestion"
>
:size="btn.size || 'small'"
:type="btn.type || `text`"
:icon="btn.icon"
:plain="btn.plain"
:style="btn.setStyle && btn.setStyle(scope.row, scope.$index)"
v-bind="btn.props"
:disabled="btn.disabled && btn.disabled(scope.row, scope.$index)"
@click.native.prevent="btn.method(scope.row, scope.$index)"
>
{{ typeof btn.label === 'string' ? btn.label : btn.label(scope.row)
}}{{ operates.length >= 2 ? ' ' : '' }}
更多
:disabled="btn.disabled && btn.disabled(scope.row, scope.$index)"
v-for="(btn, key) in operatesInner"
:key="key"
@click.native.prevent="btn.method(scope.row, scope.$index)"
>
{{ btn.label }}
v-if="!column.isShow || (column.isShow && column.isShow())"
:key="index"
v-bind="column.props"
:prop="column.prop"
:label="column.label"
:width="column.width"
:fixed="column.fixed"
show-overflow-tooltip
:align="alignDirestion"
>
{{ column.formatter(scope.row, column, scope.$index) }}
{{ column.formatter(scope.row, column, scope.$index) | dateFormat }}
class="newjump"
type="primary"
:underline="false"
v-bind="{ target: '_blank', ...column.target }"
:to="column.newjump(scope.row, column, scope.$index)"
>
{{ scope.row[column.prop] || column.content }}
:style="column.click ? 'color: #409EFF; cursor: pointer;' : null"
@click="column.click && column.click(scope.row, scope.$index)"
>
{{ scope.row[column.prop] || column.content ? scope.row[column.prop] || column.content : '-' }}
{{ `${scope.row[column.prop] && column.unit ? column.unit : ''}` }}
左右滑動查看完成代碼
頁面調(diào)用:
alignDirestion="left"
:operates="operates(this)"
operatesDir="right"
:pageHeight="48"
:export-but="exportBut(this)"
class="table-list"
:columns="columns"
:data-source="tableData"
:isDoLayout="true"
>
3.4 組件化面臨的挑戰(zhàn)
不可描述需求的開發(fā):現(xiàn)實開發(fā)中需求不可能都特別明確,對于不定性的,不可描述的需求開發(fā),組件化挑戰(zhàn)比較大,設(shè)計的組件可能需要不斷變化來適應(yīng)業(yè)務(wù)場景??捎眯院涂蓮?fù)用沖突:當(dāng)前階段,組件完全滿足功能,但是對于未來需求變化能否滿足就需要開發(fā)者有一定的前瞻性和預(yù)留擴展,以達到適應(yīng)和復(fù)用目的。組件維護:組件內(nèi)部互相獨立,要對組件可能出現(xiàn)的意外準確定位,設(shè)立相關(guān)容錯機制。
持續(xù)增長的挑戰(zhàn):組件化開發(fā)是為了更好減輕開發(fā)中的各種負擔(dān),但是組件持續(xù)增長中本身也容易成為一種負擔(dān),是否有相應(yīng)的處理手段來應(yīng)對。
組件開發(fā)規(guī)范:團隊開發(fā)中開發(fā)風(fēng)格各有差異,如何合作和理解彼此開發(fā)的組件需要制定統(tǒng)一的規(guī)范。
健壯性和可維護性:健壯性和可維護是保證組件運行乃至整個頁面、系統(tǒng)運行的關(guān)鍵。
4.總結(jié)
隨著前端領(lǐng)域的發(fā)展和開發(fā)探索,組件化思想已經(jīng)在前端開發(fā)中廣泛使用,比如流行的Vue、React框架等,都是基于組件化思想的產(chǎn)物。組件化并非一蹴而就,而是一個持續(xù)的過程。在沉淀業(yè)務(wù)組件的同時還需考慮組件包的大小,不能因為組件包的體積大而導(dǎo)致頁面加載過慢,以及組件發(fā)布前的測試等。挑戰(zhàn)也是一直存在的,但可以通過一些方法和規(guī)范去解決挑戰(zhàn),讓組件化設(shè)計更好的服務(wù)于系統(tǒng)。所以,理解組件化可以幫助開發(fā)者更好的使用框架進行工作內(nèi)容的拆分和維護,才能在實際開發(fā)中結(jié)合具體的業(yè)務(wù)場景,設(shè)計出合理的組件,實現(xiàn)真正的前端組件化。
本文題目:前端領(lǐng)域的組件化究竟是在談什么
當(dāng)前地址:http://fisionsoft.com.cn/article/ccssoic.html


咨詢
建站咨詢
