組件的拆分粒度是越細(xì)越好嗎
點擊上方 程序員成長指北,關(guān)注公眾號
回復(fù)1,加入高級Node交流群
Hello,各位小伙伴,接下來的一段時間里,我會把我的課程《Vue.js 3.0 核心源碼解析》中問題的答案陸續(xù)在我的公眾號發(fā)布,由于課程的問題大多數(shù)都是開放性的問題,所以我的答案也不一定是標(biāo)準(zhǔn)的,僅供你參考喔。
那么,回到這個問題本身,組件的拆分粒度是越細(xì)越好嗎?先說結(jié)論:并不是。為什么呢?
什么是組件
組件是一個抽象的概念,它是對一棵 DOM 樹的抽象,直觀點說,一個組件可以包含若干個原生 DOM 標(biāo)簽,舉個例子,假設(shè)我們有一個 HelloWorld 組件,如下:
<template>
<div>
<p>Hello World</p>
</div>
</template>
然后我們在頁面中去引用這個組件:
<hello-world></hello-world>
這段代碼并不會在頁面上渲染一個 <hello-world> 標(biāo)簽,而是會渲染 HelloWorld 組件中的模板內(nèi)容,即渲染一個 div,內(nèi)部包含一個 p 標(biāo)簽,顯示 Hello World 文本。
當(dāng)然,組件除了對 DOM 層面的封裝,還可以對數(shù)據(jù)、邏輯、交互等等進(jìn)行封裝,不僅如此,組件還支持嵌套,所以整個頁面就是可以由一個個嵌套的組件構(gòu)成,抽象成一棵組件樹,如下:

組件化是 Vue.js 的核心思想之一,它允許我們用模板加對象描述的方式去創(chuàng)建一個組件,再加上我們給組件注入不同的數(shù)據(jù),就可以完整地渲染出組件,那么它具體是怎么做的呢?
組件是如何渲染的
眾所周知,Vue.js 對開發(fā)者非常友好的一點是支持模板,任何合乎規(guī)范的 HTML 都是合法的 Vue 模板。Vue.js 對于模板會有一個編譯的過程(可以離線完成,也可以在運行時完成),Vue.js 在編譯模板的過程中會識別出組件標(biāo)簽,編譯生成對應(yīng)的 render 函數(shù)。
你可以借助 Vue.js 的在線模板編譯工具看一下我們前面示例 <hello-world></hello-world> 的編譯結(jié)果:
import { resolveComponent as _resolveComponent, createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_hello_world = _resolveComponent("hello-world")
return (_openBlock(), _createBlock(_component_hello_world))
}
首先,它會解析出對應(yīng)的組件定義對象,然后根據(jù)這個組件對象創(chuàng)建一個組件的 vnode。
創(chuàng)建完 vnode 后,在 Vue.js 內(nèi)部會執(zhí)行 patch 方法渲染這個 vnode,最終創(chuàng)建生成 DOM 并在頁面中渲染。所以單個組件的渲染過程大致如下:

前面說過,組件是支持嵌套的,所以整個組件樹的掛載過程,就是一個遞歸掛載組件的過程。
在組件的掛載過程中,除了前面說的創(chuàng)建和渲染 vnode 之外,內(nèi)部還創(chuàng)建了一個組件實例,用來維護(hù)組件的狀態(tài)和數(shù)據(jù),此外,還有組件初始化階段的一些響應(yīng)式數(shù)據(jù)處理,這些都是有一定耗時和內(nèi)存占用的。
因此,如果我們拆分組件的粒度過細(xì),會導(dǎo)致嵌套組件過深,顯而易見的是整個應(yīng)用的初始化時長會變長,占用的內(nèi)存空間也會變大。
如何拆分組件
那么,我們該如何拆分組件呢?其實組件的拆分通常有兩種場景。
基礎(chǔ)組件
主要是指可復(fù)用,實現(xiàn)某類功能,且不包含任何業(yè)務(wù)的組件,比如像 ElementUI 這樣的組件庫,提供的就是基礎(chǔ)組件庫,包含幾十種不同功能的基礎(chǔ)組件。
但是基礎(chǔ)組件并不一定是單一組件,它可以是一個復(fù)合組件,由若干更小的組件單元甚至是其它基礎(chǔ)組件組成。比如 Table 組件,它內(nèi)部就是由 Header、Body 組件組成,而 Body 組件,內(nèi)部又是通過循環(huán)渲染 Cell 組件組成。
有了基礎(chǔ)組件庫可以幫助你統(tǒng)一視覺規(guī)范,也會大大提升你的工作效率。
所以在日常開發(fā)工作中,如果沒有條件你就直接依賴開源的第三方組件庫開發(fā),有條件的話建議你在這些優(yōu)秀的開源組件庫基礎(chǔ)上,自研一套適合自身業(yè)務(wù)的組件庫。
業(yè)務(wù)組件
業(yè)務(wù)組件是在基礎(chǔ)組件的基礎(chǔ)上,開發(fā)出的融入業(yè)務(wù)邏輯的復(fù)合組件,通常,業(yè)務(wù)組件是為了解決某個特定的業(yè)務(wù)場景,它的復(fù)用性相比于基礎(chǔ)組件而言,沒有那么的強(qiáng)。
不過,業(yè)務(wù)組件也是可以復(fù)用的。比如彈窗登錄的場景,就有一套完整的業(yè)務(wù)邏輯以及和服務(wù)端的交互流程,我們可以把它拆成一個登錄組件,這樣就可以在頁面中方便的接入和復(fù)用。
在日常開發(fā)工作中,你要經(jīng)常思考,能不能把某類場景的業(yè)務(wù)抽象成業(yè)務(wù)組件,因為隨著業(yè)務(wù)組件的積累,工作效率也會得到明顯的提升。
因此,拆分組件主要是從代碼的復(fù)用性和維護(hù)性方面考慮,另外,從性能方面考慮,組件拆分粒度不易過細(xì)。
總結(jié)
我出這個題的主要希望你能做到以下兩點:
從源碼層面分析,你需要知道組件的初始化過程有哪些代價。
從應(yīng)用層面思考,你需要知道如何去抽象和拆分組件。
要記住,分析和思考的過程遠(yuǎn)比答案重要。


“分享、點贊、在看” 支持一波 
