# 组件拆分,设计原则

目前前端三大框架(Vue.js, Angular.js, React.js)都在引领着前端的组件化开发方向,组件化的前端开发方式的确为业务实现带来了前所未有的方便,其实组件化开发早已经具有(YUI),但如何封装一个优秀的组件,可能并不是每位前端开发者都能够做好的。

组件封装有一定的不确定性,更多时候是在做几个方面的权衡,并且在业务不断变化中,可能还会面临一些调整和重构。

组件化开发的意义有很多,一些新手会狭隘地认为只是为了复用(包括对于模块化的理解),认为只有一个地方用就没必要抽取封装为组件,但实则不尽然。

# 组件的设计遵循以下的思路

高内聚低耦合,尽可能少的暴露组件的 api,将功能尽量封装在组件内部

组件内部根据业务需求设置了一些组件默认的配置项,另外再通过不同页面传入不同配置项提高组件的通用性

设计组件的目的就是让组件进一步解耦,将配置项和模板标签分离,一方面是减少在业务逻辑组件中的代码量,另一方面就是单独抽离的配置项使得能够通过后台动态传递给前端

首先在做组件封装之前,我们要清楚的知道为什么要做组件封装,组件封装能为我们带来什么?

1.组件化是对实现的分层,是更有效地代码组合方式(组件的分层:分层架构分为四个层:展示层(presentation layer),业务层(business layer),持久层(persistence layer)和数据库层(database layer))

2.组件化是对资源的重组和优化,从而使项目资源管理更合理

3.组件化有利于单元测试

4.组件化对重构较友好

明白了以上几点我们就来讲讲组件的定义?什么是组件的定义,组件的定义就是你期望组件是什么样子的?

1.可复用的模块,完成既定功能

2.有明确的接口规定

3.有上下文依赖、外部依赖资源的定义

4.可以独立发布

搞清楚了以上几点,我们就在来谈组件的设计原则。新手常常会更多地从实现(如所用的框架 Vue 的组件实现方式)直觉角度定义组件,并且隘于视角较局限,经验较欠缺,对于职责划分不合理。

1.适用单一职责原则

2.开闭原则

3.避免太多参数

4.适用 SPOT 法则 (Single Point Of Truth,就是尽量不要重复代码)

5.追求无副作用

6.避免暴露组件内部实现

7.避免直接操作 DOM

以上原则有点太教科书,不结合长期的实践深刻理解,很难灵活运用,所以在思考一个组件时候,从这几个问题入手,引导完善组件的设计

# 这个组件可否(有必要)再分?

组件划分的依据通常是 业务逻辑、功能,要考虑各组件之间的关系是否明确(如组件树方式管理组件间依赖关系,兄弟组件不可见),以及组件的可复用度。

划分粒度的大小需要根据实际情况权衡,太小会提升维护成本,太大又不够灵活和高复用性。

每一个组件都应该有其独特的划分目的的,有的是为了复用实现,有的是为了封装复杂度清晰业务实现。

# 这个组件的依赖是否可再缩减?

缩减组件依赖可以提高组件的可复用度,常用的方法是 IoC(依赖注入),对外弱类型依赖。

# 这个组件是否对其它组件造成侵入?

一个组件的封装性不够,或者自身越界操作,就可能对自身之外造成了侵入,这种情况应该尽量避免,确保组件的生命周期能够对其影响进行有效的管理(如 destroy 后不留痕迹)。

较常见的一种情况是:组件运行时对 window 对象添加 resize 监听事件以实现组件响应视窗尺寸变化事件,这种需求的更好替代方案是:组件提供刷新方法,由父组件实现调用(最终由根组件统一处理)。

次优的方案是,当组件 destroy 前清理恢复。

一个组件不应对其它兄弟组件造成直接影响。

# 这个组件可否复用于其它类似场景中?

需要考虑需要适用的不同场景,在组件接口设计时进行必要的兼容。

# 这个组件当别人用时,会怎么想?

接口设计符合规范和大众习惯,尽量让别人用起来简单易上手,易上手是指更符合直觉。

# 假如业务需要不需要这个功能,是否方便清除?

各组件之前以组合的关系互相配合,也是对功能需求的模块化抽象,当需求变化时可以将实现以模块粒度进行调整。