前端组件化思考
前言
组件化对于任何一个业务场景复杂的前端应用以及经过多次迭代之后的产品来说都是必经之路。组件化要做的不仅仅是表面上看到的模块拆分解耦,其背后还有很多工作来支撑组件化的进行,例如结合业务特性的模块拆分策略、模块间的交互方式和构建系统等等
组件化并不是前端独有的,当今前端生态里面,React、Angular和Vue三分天下。虽然这三个框架的定位各有不同,但是它们有一个核心的共同点,那就是提供了组件化的能力。
前端实施组件化的目的
从发展的角度来看
随着技术的发展,开发的复杂度也越来越高,传统开发模式总是存在着开发效率低,维护成本高等弊端
传统开发方式效率低以及维护成本高的主要原因在于很多时候是将一个系统做成了整块应用,而且往往随着业务的增长或者变更,系统的复杂度会呈现指数级的增长,经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改,造成牵一发而动全身
我们希望一个大且复杂的场景能够被分解成几个小的部分,这些小的部分彼此之间互不干扰,可以单独开发,单独维护,而且他们之间可以随意的进行组合
从效率的角度思考
迭代速度慢,公共代码相互耦合,需要全量回归
多人协作是极其困难的一件事
代码冲突多,每次提交代码可能需要解决冲突
版本风险高,修改会影响很多需求之外的功能
从技术的角度思考
代码整体结构混乱、缺少层次
优秀的代码应该是高内聚,低耦合
龟速编译,开发体验极差
无法很好地支持A/BTest
每次发版在QA回归上耗时很久
什么是组件化
前端的组件化,其实是对项目进行自上而下的拆分,把通用的、可复用的功能以黑盒的形式封装到一个组件中,然后暴露一些开箱即用的函数和属性配置供外部组件调用,实现与业务逻辑的解耦,来达到代码间的高内聚、低耦合,实现功能模块的可配置、可复用、可扩展。
组件化的演变
组件化经历了:函数化编程思想
、模块化编程思想
和组件化编程思想
三个阶段
函数化编程思想:
- 以函数(方法)来分离行为
- 每一个函数仅在做一件事情
模块化编程思想:
- 以模块(js文件)来分离行为
- 每个模块负责一类事情
组件化编程思想:
- 以组件来分离行为
- 每个组件拥有独立的结构、视图和行为,代表一个完整的个体
组件的职能划分
组件最大的不稳定性来自于展现层,一个组件只做一件事,基于功能做好职责划分:
基础组件
容器型组件
展示型组件
业务组件
通用组件
容器型组件
一个容器性质的组件,一般当作一个业务子模块的入口,比如一个路由指向的组件;容器型组件需要知道如何获取子组件所需数据,以及这些数据的处理逻辑,并把数据和逻辑通过props提供给子组件使用。容器型组件一般是有状态组件,因为它们需要管理页面所需数据。
展示型组件
主要表现为组件是怎样渲染的,就像一个简单的模版渲染;
只通过props接受数据和回调函数,不充当数据源;
通常用props.children(react) 或者slot(vue)来包含其他组件;
可以有状态,在其生命周期内可以操纵并改变其内部状态,职责单一,将不属于自己的行为通过回调传递出去,让父级去处理。
业务组件
通常是根据最小业务状态抽象而出,业务组件虽然也具有一定的复用性,但大多数是一次性组件
通用组件
可以在一个或多个项目内通用的组件
组件化在现代项目中的职责
组件化开发方案主要关注的是在迭代开发阶段的对团队效率的提升。
1.单一职责
单一职责强调一个组件具备一项“能力”。
单一职责可以保证组件是最细的粒度,且有利于复用。但太细的粒度有时又会造成组件的碎片化。因此单一职责组件要建立在可复用的基础上,对于不可复用的单一职责组件,我们仅仅作为独立组件的内部组件即可。
单一职责同时也具备简化组件的能力,遵守该原则在一定程度上能够使代码足够简单,意味着易读、易维护。
2.封装
良好的组件封装应该隐藏内部细节和实现意义,并通过props来控制行为和输出。同时还要具备减少访问全局变量能力,因为访问全局变量会打破封装,创造了不可预测的行为。
封装能够将不用逻辑代码分离,能够帮助开发中快速定位问题。
3.可配置性
一个组件,要明确它的输入和输出分别是什么。
组件除了要展示默认的内容,还需要做一些动态的适配,比如:一个组件内有一段文本,一个图片和一个按钮;字体的颜色、图片的规则、按钮的位置、按钮点击事件的处理逻辑等,都是可以做成可配置的。
4.组合
单一责任原则描述了如何将需求拆分为组件,封装描述了如何组织这些组件,组合描述了如何将整个系统粘合在一起;
具有多个功能的组件,应该转换为多个单一职责的小组件,这些小的组件又可以组合成为一个职责更大、功能单一的组件。
5.复用
- 通常来说我们进行组件设计的目的有两种:
抽取公共功能部分,方便复用;
复杂设计/功能分解,便于代码管理和提高代码阅读性。
- 提高组件的复用性,使得一处代码的封装能够在各个不同的地方使用。复用性能够使代码的修改/编辑更加方便,只需要修改组件代码,各个引用的地方会同步进行修改和更新。
6.可测试
现在前端开发过程中一直都在强调单元测试,一个完成的项目单测是不可缺少的一部分,单测可以保证代码正确性、一部分依赖的正确性、以及减少调试时间等。
单元测试的目的不是为了减少代码覆盖率,而是为了减少bug出现的概率,以及防止bug回归。
总结
组件化并非一蹴而就,而是一个持续的过程。在沉淀业务组件的同时还需考虑组件包的大小,不能因为组件包的体积大而导致页面加载过慢,以及组件发布前的测试等。但可以通过一些方法和规范去解决挑战,让组件化设计更好的服务于系统。所以,理解组件化可以帮助开发者更好地使用框架进行工作内容的拆分和维护,才能在实际开发中结合具体的业务场景,设计出合理的组件,实现真正的前端组件化。