前端組件化思想

1.開篇

??先說說為什么要寫這篇文章吧:不知從什么時(shí)候開始蓬抄,大家相信前端摩爾定律:“每18個(gè)月鸯匹,前端難度會增加一倍”。我并不完全認(rèn)可這個(gè)數(shù)字的可靠性凡桥,但是這句話的本意我還是非撤羌#肯定的惯裕。

??是的玄叠,前端越來越簡單了欣尼,但也越來越復(fù)雜了---簡單到你可以用一個(gè)Githubstarter搭建一個(gè)框架祸穷,集成所有的全家桶性穿,涵蓋單元測試和功能測試,包括部署以及發(fā)布雷滚,甚至你開發(fā)時(shí)使用的UI庫都讓你寫不了幾行css需曾;可又復(fù)雜到如此多的框架和庫層出不窮,你還沒來得及學(xué)會官網(wǎng)的doc呢,就已經(jīng)有新的替代品了呆万,那就更別提靜下心去學(xué)習(xí)其中的源碼或推敲原理了商源,跟不上腳步強(qiáng)行搬磚自然略顯疲憊。

??正是前端飛速的發(fā)展使得前端看似簡單谋减,但若想深入?yún)s實(shí)屬不易牡彻。順便提一句,去年6月底出爹,ES8已經(jīng)發(fā)布了庄吼,沒錯(cuò),你沒看錯(cuò)严就,是不感覺學(xué)不動(dòng)了(開玩笑了总寻,其實(shí)也沒更新啥,不會再有ES5->ES6這種跨度了)梢为。

??所以渐行,我近期覺得使用的框架有些多了,得靜下心來沉淀沉淀---為什么要說寫組件化思想呢铸董?因?yàn)槲矣X得它是伴隨著前端發(fā)展的一個(gè)不可或缺的設(shè)計(jì)思想殊轴,目前幾大流行框架也都非常好的實(shí)現(xiàn)了組件化,比如React袒炉,Vue旁理。React之前用得算是比較多了,所以本篇我決定以Vue作為基礎(chǔ)我磁,去談一談前端模塊化孽文,組件化,可維護(hù)化的設(shè)計(jì)細(xì)想夺艰。

2.什么是組件化

??組件化并不是前端所特有的芋哭,一些其他的語言或者桌面程序等,都具有組件化的先例郁副。確切的說减牺,只要有UI層的展示,就必定有可以組件化的地方存谎。簡單來說拔疚,組件就是將一段UI樣式和其對應(yīng)的功能作為獨(dú)立的整體去看待,無論這個(gè)整體放在哪里去使用既荚,它都具有一樣的功能和樣式稚失,從而實(shí)現(xiàn)復(fù)用,這種整體化的細(xì)想就是組件化恰聘。不難看出句各,組件化設(shè)計(jì)就是為了增加復(fù)用性吸占,靈活性,提高系統(tǒng)設(shè)計(jì)凿宾,從而提高開發(fā)效率矾屯。

3.組件化的演變

??如果你對JS的理解還停留在jQuery的話(jQuery本身是一個(gè)非常優(yōu)秀的庫),那么請?zhí)^此文(開個(gè)玩笑)初厚。在那個(gè)時(shí)候件蚕,大部分的前端開發(fā)應(yīng)該都是十分過程式的開發(fā):操作DOM,發(fā)起ajax請求惧所,刷新數(shù)據(jù)骤坐,局部更新頁面。這樣的動(dòng)作反反復(fù)復(fù)下愈,甚至在同一個(gè)項(xiàng)目里同樣的流程也許還要重復(fù)纽绍,其實(shí)jQuery本身也有有自己模塊化的設(shè)計(jì),有時(shí)我們也會用到類似jQuery UI等不錯(cuò)的庫來減少工作量势似,但請注意拌夏,這里我只認(rèn)為它是模塊化的。

??頻繁操作DOM履因,過程式的開發(fā)方式的確不怎么樣障簿。這時(shí)開始流行MV*,比如MVC栅迄,前端開始學(xué)習(xí)后端的思想站故,講業(yè)務(wù)邏輯,UI毅舆,功能西篓,可以按照不同的文件去劃分,結(jié)構(gòu)清晰憋活,設(shè)計(jì)明了岂津,開發(fā)起來也不錯(cuò)。在這個(gè)基礎(chǔ)上悦即,又有了更加不錯(cuò)的MVVM框架吮成,它的出現(xiàn),更加簡化了前端的操作辜梳,并且將前端的UI賦予了真實(shí)意義:你所看到的任何UI粱甫,應(yīng)該都對應(yīng)其相應(yīng)的ViewModel,即你看到的view就是真實(shí)的數(shù)據(jù)冗美,并且實(shí)現(xiàn)了雙向綁定魔种,只要UI改變,UI所對應(yīng)的數(shù)據(jù)也改變粉洼,反之亦然节预。這的確很方便,但大部分的MVVM框架属韧,并沒有實(shí)現(xiàn)組件化安拟,或者說沒有很好的實(shí)現(xiàn)組件化,因?yàn)?code>MVVM最大的問題就是:

  • 1.執(zhí)行效率宵喂,只要數(shù)據(jù)改變糠赦,它下面所有監(jiān)測數(shù)據(jù)上綁定的UI一般都會去更新,效率很低锅棕,如果你操作頻繁拙泽,很可能調(diào)了幾十萬遍(有可能層次太深或者監(jiān)測了太多的數(shù)據(jù)變化)。

  • 2.由于MVVM一般需要嚴(yán)格的ViewModel的作用域裸燎,因此大部分情況不支持多次綁定顾瞻,或者只允許綁定一個(gè)根節(jié)點(diǎn)做為頂層DOM渲染,這就給組件化帶來了困難(不能獨(dú)立的去綁定部分UI)德绿。

??而后荷荤,在此基礎(chǔ)上,一些新的前端框架“取其精華移稳,去其糟粕”蕴纳,開始大力推廣前端組件化的開發(fā)方式,從這一點(diǎn)來說个粱,ReactVue是類似的古毛。

??但從框架本身來說,ReactVue是完全不同的都许,前者是單向數(shù)據(jù)流管理設(shè)計(jì)的先驅(qū)稻薇,如果非讓我做一個(gè)不恰當(dāng)?shù)谋容^的話,我覺得React+Redux是將MVC做到了極致(action->request, reducer->controller)梭稚;而后者則是后起之秀颖低,既吸取了React的數(shù)據(jù)流管理方式(Vue本身也可以用類似React的方式去開發(fā),但難度比較大而已弧烤,不是很Vue)的設(shè)計(jì)理念忱屑,也實(shí)現(xiàn)了MVVM的雙向綁定和數(shù)據(jù)監(jiān)控(這應(yīng)該是Vue的核心了),所以Vue是比較靈活的暇昂,可以按需擴(kuò)展莺戒,它才敢稱自己是漸進(jìn)式框架。

PS1: 并非討論孰好孰壞急波,兩大框架我都很喜歡从铲,因?yàn)槎挤浅:玫膶?shí)現(xiàn)了組件化。

PS2: 上面有提到模塊化澄暮,個(gè)人覺得如果更廣義的來講名段,模塊化和組件化并不在一個(gè)維度上阱扬,模塊化往往是代碼的設(shè)計(jì)和項(xiàng)目結(jié)構(gòu)的設(shè)計(jì);但很多時(shí)候在狹義的場景中伸辟,比如一個(gè)很通用的功能麻惶,也完全能夠?qū)⑵浣M件化或模塊化,這兩者此時(shí)十分相似信夫,最大的區(qū)別就是組件必定是模塊化的窃蹋,并且往往需要實(shí)例化,也應(yīng)當(dāng)賦有生命周期静稻,而模塊化往往是直接引用警没。

4.如何實(shí)現(xiàn)組件化

??我就以搜房網(wǎng)為例(最近房價(jià)居高不下,各個(gè)大佬還在吹各種牛x說房價(jià)不久后將白菜價(jià)振湾,我順便mark下看以后打誰的臉)進(jìn)行demo分析杀迹。隨手截圖如下:

demo1.png

4.1分析頁面布局

demo2.png

??從大體上來看,可以分為頂部搜索恰梢,中間內(nèi)容展示佛南。而中間內(nèi)容又分為part1,2嵌言,3三種類型嗅回。由于篇幅問題,本文只分析part1摧茴,2绵载,3

??每一個(gè)part中又可以分為header(title + link)和content(每個(gè)part不一樣)

demo3.png

4.2初步開發(fā)

如果沒有經(jīng)過任何設(shè)計(jì),也許會出現(xiàn)下面的代碼:


<template>
  <div id="app">
    <div class="nav-search">...</div>
    <div class="panel">
      <div class="part1 left">
        <div>
          <span>萬科城潤園樓盤動(dòng)態(tài)</span>
          <a href="">更多動(dòng)態(tài)>></a>
        </div>
        <div>這里是每個(gè)part里面的具體內(nèi)容</div>
      </div>
      <div class="part2 right">
        <div>
          <span>樓盤故事</span>
          <a href="">更多>></a>
        </div>
        <div>這里是每個(gè)part里面的具體內(nèi)容</div>
      </div>
      <div class="part3">
        <div>
          <span>萬科城潤園戶型</span>
          <a href="">二居(1)</a>
          <a href="">三居(4)</a>
          <a href="">四居(3)</a>
          <a href="">更多>></a>
        </div>
        <div>這里是每個(gè)part里面的具體內(nèi)容</div>
      </div>
    </div>
  </div>
</template>


其中我省略了大部分的細(xì)節(jié)實(shí)現(xiàn)苛白,實(shí)際代碼量應(yīng)該是這里的數(shù)倍娃豹。

這段代碼有幾個(gè)問題:

  • 1.part1,2购裙,3的結(jié)構(gòu)很類似懂版,有些許重復(fù)

  • 2.實(shí)際的代碼量將會很多,很難快速定位問題躏率,維護(hù)難度較大

4.3化繁為簡

首先我們可以將part1躯畴,2,3進(jìn)行分離薇芝,這樣就獨(dú)立出來三個(gè)文件蓬抄,那么結(jié)構(gòu)上將會非常清晰


<template>
  <div id="app">
    <div class="nav-search">...</div>
    <div class="panel">
      <part1 />
      <part2 />
      <part3 /> 
  </div>
</template>

這有些類似將一個(gè)大函數(shù)逐步拆解成幾部分的過程,不難想象part1夯到,2嚷缭,3中的代碼,必然是適用性很差,確切的說只有這里能夠引用阅爽。(但我看過很多項(xiàng)目的代碼路幸,就是這么干的,認(rèn)為自己做了組件化优床,抽象還不錯(cuò)(@_@))

4.4組件抽象

仔細(xì)觀察part1劝赔,2誓焦,3胆敞,正如我上面所說,它們其實(shí)是很相似的:都具有相同的外層border并附有shadow杂伟,都具有抬頭和顯示更多移层,各自內(nèi)容部分暫不細(xì)說的話,這三個(gè)完全就是一模一樣赫粥。

如此观话,我們將具有高度相似的業(yè)務(wù)數(shù)據(jù)進(jìn)行抽離,實(shí)現(xiàn)組件的抽象越平。

part.vue


<template>
  <div class="part">
    <div class="hearder">
      <span>{{ title }}</span>
      <a :href="linkForMore">{{ showMore || '更多>>' }}</a>
    </div>
    <slot name="content" />
  </div>
</template>

我們將part內(nèi)可以抽象的數(shù)據(jù)都做成了props频蛔,包括利用slot去做模版,同時(shí)showMore || '更多>>'也考慮到了part1的link名字和其他幾個(gè)part不一致的情況秦叛。

這樣一來app.vue就更加清晰化


<template>
  <div id="app">
    <div class="nav-search">...</div>
    <div class="panel">
      <part
        title="萬科城潤園樓盤動(dòng)態(tài)"
        linkForMore="#1"
        showMore="更多動(dòng)態(tài)>>"
      >
        <div slot="content">這里是part1里面的具體內(nèi)容</div>
      </part>
      <part
        title="樓盤故事"
        linkForMore="#2"
      >
        <div slot="content">這里是part2里面的具體內(nèi)容</div>
      </part>
      <part
        title="萬科城潤園戶型"
        linkForMore="#3"
      >
        <div slot="content">這里是part3里面的具體內(nèi)容</div>
      </part>
  </div>
</template>

這里有幾點(diǎn)需要說明一下:

  • 1.三個(gè)part中部分UI差異應(yīng)該在哪里定義晦溪?

比如三個(gè)part的寬度都不一樣,并且part1和part2可能要需要進(jìn)行浮動(dòng)挣跋。

必須要記住三圆,這種差異并不是組件本身的,<part />的設(shè)計(jì)本身應(yīng)該是無浮動(dòng)并且寬度占100%的避咆,至于占誰的100%舟肉,那就取決于誰引用它,至于向左還是向右浮動(dòng)查库,同樣也取決于引用它的container需要自己去定義路媚,在上面的代碼中,app.vue就應(yīng)該是<part />的container樊销,app想要的是一個(gè)左浮動(dòng)且寬度為80%的part(part1)整慎,右浮動(dòng)且寬度為20%的part(part2)和一個(gè)寬度為100%的part(part3),但它們都是part现柠,所以應(yīng)該由app來設(shè)置這些差異院领。

記住這一點(diǎn),將給你的抽象和擴(kuò)展但來事半功倍的效果够吩。

  • 2.三個(gè)part中的數(shù)據(jù)差異應(yīng)該在哪里定義比然?

比如part3中,其他的part只有一個(gè)類似更多>>的link周循,但是它卻有多個(gè)(一居强法,二居...)万俗。

這里我推薦將這種差異體現(xiàn)在組件內(nèi)部,設(shè)計(jì)方法也很多:

比如可以將link數(shù)組化為links饮怯;

比如可以將更多>>看作是一個(gè)default的link闰歪,而多余的部分則是用戶自定義的特殊link,這兩者合并組成了links蓖墅。用戶自定義的默認(rèn)是沒有的库倘,需要引用組件時(shí)進(jìn)行傳入。

總之论矾,只要有數(shù)據(jù)差異化教翩,就應(yīng)該結(jié)合組件本身和業(yè)務(wù)上下文將差異合理的消除在內(nèi)部。

  • 3.注意組件內(nèi)數(shù)據(jù)的命名方式

一個(gè)通用的贪壳,可擴(kuò)展性高的組件饱亿,必然是有非常合理的命名的,比如觀察一些組件庫的命名闰靴,總會出現(xiàn)類似list,data,content,name,key,callback,className等名詞彪笼,絕對不會出現(xiàn)我們系統(tǒng)中的類似iterationList, projectName等業(yè)務(wù)名詞,這些名詞和任一產(chǎn)品和應(yīng)用都無關(guān)蚂且,它與自身抽象的組件有關(guān)配猫,只表明組件內(nèi)部的數(shù)據(jù)含義,偶爾也會代表其結(jié)構(gòu)膘掰,所以只有這樣章姓,才能讓用戶通用。

我們在組件化時(shí)识埋,也需要遵循這種設(shè)計(jì)原則凡伊,但庫往往是想讓廣大開發(fā)者通用,而我們可以降低scope窒舟,做到在整個(gè)app內(nèi)通用即可系忙。所以從這個(gè)角度來說,好的組件化必然有好的BA和UX惠豺,這是大實(shí)話

5.寫在最后

你也許會認(rèn)為這樣抽象沒有太大的必要性银还,畢竟它只是一段靜態(tài)UI(pure component),但任何的設(shè)計(jì)都是基于一定的復(fù)雜度才衍生出來的洁墙,其實(shí)大部分情況下這種設(shè)計(jì)都是需要將功能邏輯代碼也納入其中的蛹疯,并不光只是UI(如antd, element-ui等),我這里舉的例子也相對比較簡單热监,并不想有太多的代碼捺弦。

個(gè)人認(rèn)為在一個(gè)大型前端項(xiàng)目中,這種組件化的抽象設(shè)計(jì)是很重要的,不僅增加了復(fù)用性提高了工作效率列吼,從某種程度上來說也反應(yīng)了程序員對業(yè)務(wù)和產(chǎn)品設(shè)計(jì)的理解幽崩,一旦有問題或者需要功能擴(kuò)展時(shí),你就會發(fā)現(xiàn)之前的設(shè)計(jì)是多么的make sense(畢竟需求總是在變哪)寞钥。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末慌申,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子理郑,更是在濱河造成了極大的恐慌蹄溉,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件香浩,死亡現(xiàn)場離奇詭異类缤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)邻吭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宴霸,“玉大人囱晴,你說我怎么就攤上這事∑靶唬” “怎么了畸写?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長氓扛。 經(jīng)常有香客問我枯芬,道長,這世上最難降的妖魔是什么采郎? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任千所,我火速辦了婚禮,結(jié)果婚禮上蒜埋,老公的妹妹穿的比我還像新娘淫痰。我一直安慰自己,他們只是感情好整份,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布待错。 她就那樣靜靜地躺著,像睡著了一般烈评。 火紅的嫁衣襯著肌膚如雪火俄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天讲冠,我揣著相機(jī)與錄音瓜客,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛忆家,可吹牛的內(nèi)容都是我干的犹菇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼芽卿,長吁一口氣:“原來是場噩夢啊……” “哼揭芍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起卸例,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤称杨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后筷转,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姑原,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年呜舒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锭汛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡袭蝗,死狀恐怖唤殴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情到腥,我是刑警寧澤朵逝,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站乡范,受9級特大地震影響配名,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晋辆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一渠脉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧栈拖,春花似錦连舍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贴彼,卻和暖如春潜腻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背器仗。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工融涣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留童番,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓威鹿,卻偏偏與公主長得像剃斧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子忽你,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容