场景
我们有如下的业务场景:
一个很简单的Tag标签,标签有如下分类,每个代表打卡结果,其中迟到、早退、严重迟到为一个颜色,出差为一个颜色,缺卡、迟到旷工为一个颜色,请假为一个颜色;而正常的打卡结果又是只为单独的文字:
❌差的做法(不推荐):
import React, { Component } from 'react'
import styles from './style.module.less'
import classnames from 'classnames'
/**
* 考勤结果枚举
* @type {{}}
*/
const Eum = {
normal: '正常',
normal_by_user: '正常(补)',
normal_by_admin: '正常(调)',
late: '迟到',
serious_late: '严重迟到',
absenteeism: '旷工迟到',
leave_early: '早退',
absence: '缺卡',
ask_for_leave: '请假',
official_leave: '公出',
business_trip: '出差'
}
const Tag = ({ text, onlyText = false }) => {
let same1 = (text === 'late') || (text === 'serious_late') || (text === 'absence')
let same2 = (text === 'absence') || (text === 'absenteeism')
const renderSty = same1 ? 'later' : same2 ? 'over' : text
const show = Eum[text] ? Eum[text] : ''
const wrapClass = classnames({
[styles[renderSty]]: !onlyText,
[styles['wrap_tag']]: !onlyText,
only_text: onlyText
})
return <div className={wrapClass}>{show}</div>
}
export default Tag
使用:
import Tag from '@/component/Tag'
const Test = () => {
// 一写判断
return <Tag text='' onlyText={} />
}
export default Test
上面代码的做法是吧,所有的这个业务写在一个组件里面,但是这有许多不好的地方;
- 耦合度太高,比较混乱,太依据业务,会比较难维护。
- 在整个应用上,组件不通用。我想在其他地方继续使用Tag,发现它和业务捆绑的太死了难以复用。
- 使用上需要有两个判断:后端返回的结果text对应枚举的文字,onlyText是否只展示纯文本。有点冗余
组件解耦合
把组件和业务的关联性变低,解耦合,让组件更通用,更容易维护,接下来我们实操下。
把Tag改为一个通用的组件,只要传入对应的文字就展示对应的文字,可以根据预设的color来生产对应的classname(需要在样式上写好类名即可,如果下次有增加新的直接增加预设样式即可)
改造后如下:
import React, { Component } from 'react'
import styles from './style.module.less'
import classnames from 'classnames'
/**
* 打卡结果标签
*/
const Tag = ({ text = '', color = '', background = '', style }) => {
// 预设color集合
const preSetColorList = ['pink', 'green', 'blue', 'orange']
const findPreSetColor = (color) => {
return !!preSetColorList.find(item => item === color)
}
const wrapClass = classnames({
[styles['wrap_tag']]: true,
[styles[color]]: true,
})
const tagStyle = {
color: color && !findPreSetColor(color) ? color : undefined,
background: background,
...style
}
return <div className={wrapClass} style={tagStyle}>{text}</div>
}
export default Tag
不使用antd的tag是因为满足不了需求,UI有偏差,场景不复杂,自己写更快。
使用:
import Tag from '@/component/Tag'
import TagStyleListConfig from './config'
const Test = () => {
return TagStyleListConfig[text] ? <Tag {...TagStyleListConfig[text]}/> : ''
}
export default Test
写一份业务需要的映射配置,这样做是为了保持业务和组件分离,逻辑更清晰:
//映射枚举对象,用来展示对应需要展示的内容
export const TagStyleListConfig = {
none: {
text: '缺卡',
color: 'pink'
},
early: {
text: '早退',
color: 'orange'
},
later: {
text: '迟到',
color: 'orange'
},
laterSeri: {
text: '严重迟到',
color: 'orange'
},
laterNone: {
text: '旷工迟到',
color: 'orange'
},
leave: {
text: '请假',
color: 'green'
}
}
通过TagStyleListConfig建立一个映射对应内容,这样就不用写多个判断。
并且解决了最初的几个问题:
- 解决了高耦合问题,例如直接增加color就可以增加其他场景:
// 预设color集合
const preSetColorList = ['pink', 'green', 'blue', 'orange', '增加其他类名和样式']
- 通用问题,在其他模块上仍能使用,与业务划分,更容易维护:
<Tag text='测试' color='test'/>
通过以上例子,我们利用了解耦的方法+映射,生产出对应易于组件维护和复用,代码逻辑更清楚。