本文已参与「新人创作礼」活动,一起开启掘金创作之路。
引言
组件封装有一定的不确定性,更多时候是在做几个方便的权衡,平切在业务不断变化中,可能还要面临一些调整和重构。
组件化开发的意义有很多,一些新手会狭隘的认为只是为了复用(包括对应模块化的理解),认为只有一个地方用久没必要抽取封装为组件,但实则不然:
- 组件化是对实现的分层,是更有效的代码组合方式。
- 组件化是对资源的重组和优化,从而使项目资源管理更合理。
- 组件化更有利于单元测试。前端如何进行单元测试
- 组件化对于重构比较友好。
组件与模块
模块(Module)通常强调的是职责(分离,内聚),组件是可以复用模块和相关依赖的封装。低耦合,高内聚
组件可以如下定义:
- 可复用的模块,完成既定功能。
- 有明确的接口规定。
- 有上下文依赖、外部依赖资源的定义。
- 可以独立发布。
组件设计的原则
- 单一职责原则。 SOLID 设计原则
- 开放封闭原则。 SOLID 设计原则
- 追求短小精悍。代码整洁之道中命名规范
- 避免太多参数
- SPOT原则 (保持任何一个知识点,在系统中唯一的,明确的。「尽量不要重复代码」出自《The Art of Unix Programming》)
- 追求无副作用。js 函数式编程 - 纯函数和副作用的概念
- 追求引用透明。js 函数式编程 - 引用透明概念
- 避免暴露组件内部实现。
- 避免直接操作 DOM。
- 适用好莱坞法则。 好莱坞法则
- 入口处检查参数的有效性,出口处检查返回的正确性。
自省的几个问题
以上原则有点太教科书。不结合长期的时间深刻理解,很难灵活运用,所以设计了几个自省问题。在思考一个组件的时候,从几个问题入手,引导完善组件的设计。
是否有必要拆分组件?
组件划分的依据通常是业务逻辑、功能,要考虑各组件之间的关系是否明确(例如:组件树方式管理组件间依赖关系,兄弟组件不可见),以及组件的可复用度。
划分力度的大小需要实际情况权衡,太小会提升维护成本,太大又不够灵活和高复用性。每一个组件都应该有其独特的划分目的,有的是为了复用实现,有的是为了封装复杂度清晰业务实现。
这个组件的依赖是否能再缩减?
缩减组件依赖可以提高组件的可复用度,常用的方法是 IoC(控制反转)和 DI(依赖注入),对外弱类型依赖。控制反转、依赖注入
这个组件是否对其他组件造成入侵?
一个组件的封装性不够,或自身越界操作,就可能对自身之外造成了入侵,这种情况应该尽量避免,确保组件的声明周期能够对其影响进行有效的管理(如 destroy 后不留痕迹)。
常见的一种场景:组件运行时,window 对象添加 resize 监听组件视窗尺寸变化,比较好的方案是:组件提供刷新方法,由父组件实现调用(最终由根组件统一处理)。其次方案:组件 destroy 前清理恢复。
一个组件不应该对其他兄弟组件造成影响。
这个组件是否可以用于其他类似场景?
需要考虑适用的不同场景,在组件接口设计时进行必要的兼容。同时一定要考虑业务实际情况。
别人使用这个组件,能否快速上手?
接口设计符合规范和大众习惯,尽量让别人用起来简单上手。
假如业务不需要这个功能,是否方便清除?
各组件之前以组合的关系互相配合,也是对功能需求的模块化抽象,当需求变化时可以将实现以模块粒度进行调整。
总结
前端组件化我认为更多的还是要先有组件化的思想才能更好的实践。实现组件化的手段工具有很多,重要的还是要有组件化的思想,编码前多思考。但是又要注意不要过度设计组件。