mice.jpg前言
自从三大框架以来,现在前端开发都是以面向组件开发为主
相信同学开发的组件连起来可以绕地球一圈
当我们拿到一个页面(如下),脑子里快速把页面划分了几块,然后迅速进行coding
问题
那么问题来了。
组件构成是什么?
划分的组件到底是什么粒度?
划分的组件怎么分类?
划分的组件如何更好的复用?
让我们一个个回答吧
组件的构成
一个完整的具备功能的 UI 组件的构成,有结构(structure)、表现(presentation)和行为(behavior)这三个方面。
结构
- 视觉结构(内容结构,布局样式)✖
- 内容结构(html视图结构描述)▲
表现
- 主题风格/皮肤(UX审美想法) ●
行为
- 交互逻辑(交互想法) ✖
- 业务逻辑(实际业务规则)●
● 经常变动 ▲ 容易变动 ✖ 不怎么变动
对于不怎么变动的东西,就要考虑问题
1.在某些场景可否把视图抽离出来,让页面复用,比如Mice下的[新增页面]和[编辑页面]
2.某些组件是否可以单独抽离创建一个项目,比如租车,用车,包车。
3.某些小而好用的组件可否抽离出来放入hl-ui里面,让更多的同学去用。
...
对于经常变动的东西
1.在某些场景可否把文字都抽离出来,达到快速上线的目的。
2.可否把一些功能做成配置项,让业务人员去配置。
3.是否要把这一块功能让外部去实现,给予更大的空间。
...
划分的组件到底是什么粒度? 原子设计原则
按照原子设计原则,我们组件应分为五种
原子组件
原子组价是组成所有组件的最基础的元素,具有不可再分特性。
如上图<span style="color:red">红色区域</span>。一个按钮,一个文案,一个线,一个icon。
通常是游览器提供或者框架库内提供类似Button, Input(虽然有些是div模拟等实现,有些甚至很花哨,但组件设计语言上,不管什么样的Button都属于原子组件)
分子组件
分组组件是几个原子组件组成的组件。例:Label + Input 或者 Tabs。具有一定可操作性。
如上图<span style="color:blue">蓝色框区域</span>。
生物组件
生物组件由原子组件和分子组件组成,更专注于某一独立模块区域功能。例:列表, 日期选择,Dialog,等hl-ui里大部分组件。
如上图<span style="color:green">绿色框区域</span>。
模板组件
模板组件由原子组件,分子组件,生物组件组成,更加完整的一块功能,如页面的基本信息模块,添加服务模块。
如上图<span style="color:rgba(232,139,0,1)">黄色区域</span>。
页面组件
页面组件是由以上所有组件完成。非常完成的一大块业务逻辑。
来自于atomicdesign
Info
那我们知道这个有什么用呢?
当我决定哪个组件是什么类型后,就应该知道属于他的“位置”,对这个组件加以“约束”,有个较为清晰的组件类型划分界限。
组件分类
按功能性划分
atom1.jpg按业务组件与UI组件划分
业务组件和业务强绑定的组件
UI组件称为基础组件,更多的被复用,不耦合任何业务功能。一般是由Hl-ui等框架提供.
按纯组件与非纯组件划分
纯组件更像纯函数,指的是当Props,state相同,则组件展示完全相同,不依赖任何接口/外部变量。
在React下,可用Component 和 PureComponent区分。
按布局组件和内容组件
布局组件,如Grid, Layout,栅格化等
内容组件则是实实在在看的见得组件如 Input, Label等
按是否是纯展示组件
分纯展示的组件和有操作的组件
tips
如果是纯展示组件
在React下面就可以考虑用 PureComponent。
在Vue下面就可以用Object.freeze 和 deepFreeze来减少不必要的Observer
deepFreeze实现如下
// 深冻结函数.
function deepFreeze(obj) {
// 取回定义在obj上的属性名
var propNames = Object.getOwnPropertyNames(obj);
// 在冻结自身之前冻结属性
propNames.forEach(function(name) {
var prop = obj[name];
// 如果prop是个对象,冻结它
if (typeof prop == 'object' && prop !== null)
deepFreeze(prop);
});
// 冻结自身(no-op if already frozen)
return Object.freeze(obj);
}
组件如何更好的复用?
单一原则
一个组件应该做一件事情。
说烂的高内聚,低耦合。
但往往我们在“合适”之间做很多取舍。
这个“取舍”不仅在当下,也在项目的变化中不断的“再取舍”
KISS原则 (Keep it Simple Stupid)
Essentially, if the component needs no state - use stateless functions.
如果组件没有状态,则使用无状态组件
Perf matters: Stateless fns > ES6 class components > React.createClass()
性能上比较: 无状态函数 > 有状态函数 > class组件
Don’t pass any more props than required {...this.props} only if the list is big -- if not pass individual props.
最小化 props(接口). 不要传递超过要求的 props
Too much flows of control (If-else variations) inside the component is usually a red-flag. This most likely means - need to split up the component or create a separate variation.
如果组件内部存在较多条件控制流, 则需要对组件进行抽取
Don’t optimize prematurely - Making the current component reusable with current variations known.
不要过早优化. 只要求组件在当前需求下可被复用, 然后随机应变
来自于react-bits
可配置性
明确知道该组件输入与输出,外部传入Props,和内部State状态。暴露的方法与数据的传递。
生命周期
一个好的组件有很强的生命周期管理,入参是什么,在每一个阶段该干什么。
例如:
React 中提供了一些生命周期函数:componentWillMount,componentDidMount,componentWillReceiveProps,shouldComponentUpdate,componentWillUpdate,componentDidUpdate,render,componentWillUnmount,componentDidCatch(React v16)。
Vue 中提供了一些生命周期函数:beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed,errorCapture,errorCaptured(Vue v2.5)。
一键换肤
这个仅针对于UI组件,应前期规划好,为了后期换皮肤。
国际化
国际好有2个好处
1.静态资源分离
2.多语言
总结
如何写好一个组件是一个长久的话题,环境在变,写法在变,不变的是我们对优雅的追求。
网友评论