本文是笔者写组件设计的第七篇文章, 今天带你们实现一个自带主题且可关闭的Alert组件, 该组件在诸如Antd或者elementUI等第三方组件库中都会出现,主要用来提供系统的用户反馈.javascript
之因此会写组件设计相关的文章,是由于做为一名前端优秀的前端工程师,面对各类繁琐而重复的工做,咱们不该该循序渐进的去"辛勤劳动",而是要根据已有前端的开发经验,总结出一套本身的高效开发的方法.css
前端组件通常会划分为以下几种类型:html
因此咱们在设计组件系统的时候能够参考如上分类去设计,该分类也是antd, element, zend等主流UI库的分类方式.前端
若是对于react/vue组件设计原理不熟悉的,能够参考个人以前写的组件设计系列文章:vue
笔者已经将组件库发布到npm上了, 你们能够经过npm安装的方式体验组件.java
在开始组件设计以前但愿你们对css3和js有必定的基础,并了解基本的react/vue语法.咱们先看看实现后的组件效果:node
按照以前笔者总结的组件设计原则,咱们第一步是要确认需求. 一个警告提示(Alert)组件会有以下需求点:react
需求收集好以后,做为一个有追求的程序员, 会得出以下线框图: webpack
对于react选手来讲,若是没用typescript,建议你们都用PropTypes, 它是react内置的类型检测工具,咱们能够直接在项目中导入. vue有自带的属性检测方式,这里就不一一介绍了.css3
经过以上需求分析, 咱们发现实现一个Alert很是简单, 它属于反馈型组件,因此不会涉及到太多功能.接下来咱们就来看看具体实现.
首先咱们先根据需求将组件框架写好,这样后面写业务逻辑会更清晰:
import classnames from 'classnames' import styles from './index.less' /** * 警告提示组件 * @param {style} object 更改Alert样式 * @param {closable} bool 是否显示关闭按钮, 默认不显示 * @param {closeText} string|reactNode 自定义关闭按钮 * @param {message} string 警告提示内容 * @param {description} string 警告提示的辅助性文字 * @param {type} string 警告的类型 * @param {onClose} func 关闭时触发的事件 */ function Alert(props) { const { style, closable, closeText, message, description, type, onClose } = props return <div className={styles.xAlertWrap}> <div className={styles.alertMes}>{ message }</div> <div className={styles.alertDesc}>{ description }</div> <span className={styles.closeBtn}>{ closeText ? closeText : 'x' }</span> </div> } export default Alert 复制代码
有了这个框架,咱们来一步步往里面实现内容吧.
这几个功能在框架搭建好以后已经部分实现了,是由于他们都比较简单,不会牵扯到其余复杂逻辑.只须要对外暴露属性并使用属性便可. 具体实现以下:
function Alert(props) { const { style, closable, closeText, message, description, type, onClose } = props return <div className={classnames(styles.xAlertWrap, styles[type] || styles.warning)} style={{ ...style }} > <div className={styles.alertMes}>{ message }</div> <div className={styles.alertDesc}>{ description }</div> <span className={styles.closeBtn}>{ closeText ? closeText : 'x' }</span> </div> } 复制代码
以上代码能够发现笔者采用了classnames这个第三方工具, 他能够组合咱们的class以实现更灵活的配置. 对于type的实现,个人思路是提早预制好几种类型样式, 经过用户手动配置来匹配到对应的样式:
.xAlertWrap { box-sizing: border-box; position: relative; padding: 5px 12px; margin-bottom: 16px; border-radius: 3px; &.success { background-color: #f6ffed; border: 1px solid #b7eb8f; } &.info { background-color: #e6f7ff; border: 1px solid #91d5ff; } &.error { background-color: #fffbe6; border: 1px solid #ffe58f; } &.warning { background-color: #fff1f0; border: 1px solid #ffa39e; } } 复制代码
closable主要是用来让用户能手动关闭Alert,onClose是对外暴露的关闭时的方法, 由于不必也不须要向外暴露属性来让Alert关闭, 因此最好的方式是在组件内部实现, 咱们会经过useState这个钩子来处理,代码以下:
function Alert(props) { const { style, closable, closeText, message, description, type, onClose } = props let [visible, setVisible] = useState(true) const handleColse = () => { setVisible(false) onClose && onClose() } return visible ? <div className={classnames(styles.xAlertWrap, styles[type] || styles.warning)} style={{ opacity: visible ? '1' : '0', ...style }} > <div className={styles.alertMes}>{ message }</div> <div className={styles.alertDesc}>{ description }</div> { !!closable && <span className={styles.closeBtn} onClick={handleColse}>{ closeText ? closeText : 'x' }</span> } </div> : null } 复制代码
经过控制visible来控制Alert的出现和消失, 而且当点击关闭按钮时能调用外部暴露的onClose方法.
import PropTypes from 'prop-types' // ... Alert.propTypes = { style: PropTypes.object, closable: PropTypes.bool, closeText: PropTypes.oneOfType([ PropTypes.string, PropTypes.element ]), message: PropTypes.string, description: PropTypes.string, type: PropTypes.string, onClose: PropTypes.func } 复制代码
关于prop-types的使用官网上有很详细的案例,这里说一点就是oneOfType的用法, 它用来支持一个组件多是多种类型中的一个. 组件完整css代码以下:
.xAlertWrap { box-sizing: border-box; position: relative; padding: 5px 12px; margin-bottom: 16px; border-radius: 3px; &.success { background-color: #f6ffed; border: 1px solid #b7eb8f; } &.info { background-color: #e6f7ff; border: 1px solid #91d5ff; } &.error { background-color: #fffbe6; border: 1px solid #ffe58f; } &.warning { background-color: #fff1f0; border: 1px solid #ffa39e; } .alertMes { margin-bottom:5px; color: rgba(0, 0, 0, 0.85); font-size: 14px; line-height: 1.5em; } .alertDesc { color: rgba(0, 0, 0, 0.65); font-size: 14px; line-height: 1.5em; word-break: break-all; } .closeBtn { position: absolute; right: 8px; top: 5px; color: rgba(0, 0, 0, 0.4); cursor: pointer; } } 复制代码
经过以上步骤, 一个健壮的的Alert组件就完成了,关于代码中的css module和classnames的使用你们能够本身去官网学习,很是简单.若是不懂的能够在评论区提问,笔者看到后会第一时间解答.
咱们能够经过以下方式使用它:
<Alert message="舒适提示,你忘带口罩了" /> <Alert message="舒适提示,你注册成功" type="success" /> <Alert message="错误提示,你没洗手了" type="error" /> <Alert message="提示: 咱们开始吧" type="info" /> <Alert message="提示: 我能够关闭了" type="info" closable onClose={() => { alert(111) }} /> <Alert message="注册成功" description="你在本网站已经注册成功,谢谢您的支持和反馈,多交流真正的技术吧" closable type="success" /> 复制代码
笔者已经将实现过的组件发布到npm上了,你们若是感兴趣能够直接用npm安装后使用,方式以下:
npm i @alex_xu/xui // 导入xui import { Button, Skeleton, Empty, Progress, Tag, Switch, Drawer, Badge, Alert } from '@alex_xu/xui' 复制代码
该组件库支持按需导入,咱们只须要在项目里配置babel-plugin-import便可,具体配置以下:
// .babelrc "plugins": [ ["import", { "libraryName": "@alex_xu/xui", "style": true }] ] 复制代码
npm库截图以下:
后续笔者将会继续实现
等组件, 来复盘笔者多年的组件化之旅.
若是想获取组件设计系列完整源码, 或者想学习更多H5游戏, webpack,node,gulp,css3,javascript,nodeJS,canvas数据可视化等前端知识和实战,欢迎在公号《趣谈前端》加入咱们的技术群一块儿学习讨论,共同探索前端的边界。