组件的拆分粒度是越细越好吗
点击上方 程序员成长指北,关注公众号
回复1,加入高级Node交流群
Hello,各位小伙伴,接下来的一段时间里,我会把我的课程《Vue.js 3.0 核心源码解析》中问题的答案陆续在我的公众号发布,由于课程的问题大多数都是开放性的问题,所以我的答案也不一定是标准的,仅供你参考喔。
那么,回到这个问题本身,组件的拆分粒度是越细越好吗?先说结论:并不是。为什么呢?
什么是组件
组件是一个抽象的概念,它是对一棵 DOM 树的抽象,直观点说,一个组件可以包含若干个原生 DOM 标签,举个例子,假设我们有一个 HelloWorld
组件,如下:
<template>
<div>
<p>Hello World</p>
</div>
</template>
然后我们在页面中去引用这个组件:
<hello-world></hello-world>
这段代码并不会在页面上渲染一个 <hello-world>
标签,而是会渲染 HelloWorld
组件中的模板内容,即渲染一个 div
,内部包含一个 p
标签,显示 Hello World
文本。
当然,组件除了对 DOM 层面的封装,还可以对数据、逻辑、交互等等进行封装,不仅如此,组件还支持嵌套,所以整个页面就是可以由一个个嵌套的组件构成,抽象成一棵组件树,如下:
组件化是 Vue.js 的核心思想之一,它允许我们用模板加对象描述的方式去创建一个组件,再加上我们给组件注入不同的数据,就可以完整地渲染出组件,那么它具体是怎么做的呢?
组件是如何渲染的
众所周知,Vue.js 对开发者非常友好的一点是支持模板,任何合乎规范的 HTML 都是合法的 Vue 模板。Vue.js 对于模板会有一个编译的过程(可以离线完成,也可以在运行时完成),Vue.js 在编译模板的过程中会识别出组件标签,编译生成对应的 render 函数。
你可以借助 Vue.js 的在线模板编译工具看一下我们前面示例 <hello-world></hello-world>
的编译结果:
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))
}
首先,它会解析出对应的组件定义对象,然后根据这个组件对象创建一个组件的 vnode
。
创建完 vnode
后,在 Vue.js 内部会执行 patch
方法渲染这个 vnode
,最终创建生成 DOM 并在页面中渲染。所以单个组件的渲染过程大致如下:
前面说过,组件是支持嵌套的,所以整个组件树的挂载过程,就是一个递归挂载组件的过程。
在组件的挂载过程中,除了前面说的创建和渲染 vnode
之外,内部还创建了一个组件实例,用来维护组件的状态和数据,此外,还有组件初始化阶段的一些响应式数据处理,这些都是有一定耗时和内存占用的。
因此,如果我们拆分组件的粒度过细,会导致嵌套组件过深,显而易见的是整个应用的初始化时长会变长,占用的内存空间也会变大。
如何拆分组件
那么,我们该如何拆分组件呢?其实组件的拆分通常有两种场景。
基础组件
主要是指可复用,实现某类功能,且不包含任何业务的组件,比如像 ElementUI 这样的组件库,提供的就是基础组件库,包含几十种不同功能的基础组件。
但是基础组件并不一定是单一组件,它可以是一个复合组件,由若干更小的组件单元甚至是其它基础组件组成。比如 Table
组件,它内部就是由 Header
、Body
组件组成,而 Body
组件,内部又是通过循环渲染 Cell
组件组成。
有了基础组件库可以帮助你统一视觉规范,也会大大提升你的工作效率。
所以在日常开发工作中,如果没有条件你就直接依赖开源的第三方组件库开发,有条件的话建议你在这些优秀的开源组件库基础上,自研一套适合自身业务的组件库。
业务组件
业务组件是在基础组件的基础上,开发出的融入业务逻辑的复合组件,通常,业务组件是为了解决某个特定的业务场景,它的复用性相比于基础组件而言,没有那么的强。
不过,业务组件也是可以复用的。比如弹窗登录的场景,就有一套完整的业务逻辑以及和服务端的交互流程,我们可以把它拆成一个登录组件,这样就可以在页面中方便的接入和复用。
在日常开发工作中,你要经常思考,能不能把某类场景的业务抽象成业务组件,因为随着业务组件的积累,工作效率也会得到明显的提升。
因此,拆分组件主要是从代码的复用性和维护性方面考虑,另外,从性能方面考虑,组件拆分粒度不易过细。
总结
我出这个题的主要希望你能做到以下两点:
从源码层面分析,你需要知道组件的初始化过程有哪些代价。
从应用层面思考,你需要知道如何去抽象和拆分组件。
要记住,分析和思考的过程远比答案重要。
“分享、点赞、在看” 支持一波