组件的拆分粒度是越细越好吗

程序员成长指北

共 2826字,需浏览 6分钟

 · 2021-08-05

点击上方 程序员成长指北,关注公众号

回复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 组件,它内部就是由 HeaderBody 组件组成,而 Body 组件,内部又是通过循环渲染 Cell 组件组成。

有了基础组件库可以帮助你统一视觉规范,也会大大提升你的工作效率。

所以在日常开发工作中,如果没有条件你就直接依赖开源的第三方组件库开发,有条件的话建议你在这些优秀的开源组件库基础上,自研一套适合自身业务的组件库。

  • 业务组件

业务组件是在基础组件的基础上,开发出的融入业务逻辑的复合组件,通常,业务组件是为了解决某个特定的业务场景,它的复用性相比于基础组件而言,没有那么的强。

不过,业务组件也是可以复用的。比如弹窗登录的场景,就有一套完整的业务逻辑以及和服务端的交互流程,我们可以把它拆成一个登录组件,这样就可以在页面中方便的接入和复用。

在日常开发工作中,你要经常思考,能不能把某类场景的业务抽象成业务组件,因为随着业务组件的积累,工作效率也会得到明显的提升。

因此,拆分组件主要是从代码的复用性和维护性方面考虑,另外,从性能方面考虑,组件拆分粒度不易过细。

总结

我出这个题的主要希望你能做到以下两点:

  1. 从源码层面分析,你需要知道组件的初始化过程有哪些代价。

  2. 从应用层面思考,你需要知道如何去抽象和拆分组件。

要记住,分析和思考的过程远比答案重要。

如果觉得这篇文章还不错
点击下面卡片关注我
来个【分享、点赞、在看】三连支持一下吧

   “分享、点赞在看” 支持一波 

浏览 43
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报