如何写好一个组件

前言
自从三大框架以来,现在前端开发都是以面向组件开发为主
相信同学开发的组件连起来可以绕地球一圈
当我们拿到一个页面(如下),脑子里快速把页面划分了几块,然后迅速进行coding

mice.jpg

问题
那么问题来了。
组件构成是什么?
划分的组件到底是什么粒度?
划分的组件怎么分类?
划分的组件如何更好的复用?
让我们一个个回答吧

组件的构成

一个完整的具备功能的 UI 组件的构成,有结构(structure)、表现(presentation)和行为(behavior)这三个方面。

结构

  • 视觉结构(内容结构,布局样式)✖
  • 内容结构(html视图结构描述)▲

表现

  • 主题风格/皮肤(UX审美想法) ●

行为

  • 交互逻辑(交互想法) ✖
  • 业务逻辑(实际业务规则)●

● 经常变动 ▲ 容易变动 ✖ 不怎么变动


对于不怎么变动的东西,就要考虑问题
1.在某些场景可否把视图抽离出来,让页面复用,比如Mice下的[新增页面]和[编辑页面]
2.某些组件是否可以单独抽离创建一个项目,比如租车,用车,包车。
3.某些小而好用的组件可否抽离出来放入hl-ui里面,让更多的同学去用。
...

对于经常变动的东西
1.在某些场景可否把文字都抽离出来,达到快速上线的目的。
2.可否把一些功能做成配置项,让业务人员去配置。
3.是否要把这一块功能让外部去实现,给予更大的空间。
...

划分的组件到底是什么粒度? 原子设计原则

按照原子设计原则,我们组件应分为五种

原子组件

原子组价是组成所有组件的最基础的元素,具有不可再分特性。
如上图红色区域。一个按钮,一个文案,一个线,一个icon。
通常是游览器提供或者框架库内提供类似Button, Input(虽然有些是div模拟等实现,有些甚至很花哨,但组件设计语言上,不管什么样的Button都属于原子组件)

分子组件

分组组件是几个原子组件组成的组件。例:Label + Input 或者 Tabs。具有一定可操作性。
如上图蓝色框区域

生物组件

生物组件由原子组件和分子组件组成,更专注于某一独立模块区域功能。例:列表, 日期选择,Dialog,等hl-ui里大部分组件。
如上图绿色框区域

模板组件

模板组件由原子组件,分子组件,生物组件组成,更加完整的一块功能,如页面的基本信息模块,添加服务模块。
如上图黄色区域

页面组件

页面组件是由以上所有组件完成。非常完成的一大块业务逻辑。

来自于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.多语言

总结

如何写好一个组件是一个长久的话题,环境在变,写法在变,不变的是我们对优雅的追求。

你可能感兴趣的:(如何写好一个组件)