《精通react/vue组件设计》之实现一个健壮的警告提示(Alert)组件

前言

本文是笔者写组件设计的第七篇文章, 今天带大家实现一个自带主题且可关闭的Alert组件, 该组件在诸如Antd或者elementUI等第三方组件库中都会出现,主要用来提供系统的用户反馈.

之所以会写组件设计相关的文章,是因为作为一名前端优秀的前端工程师,面对各种繁琐而重复的工作,我们不应该按部就班的去"辛勤劳动",而是要根据已有前端的开发经验,总结出一套自己的高效开发的方法.

前端组件一般会划分为如下几种类型:

  • 通用型组件: 比如Button, Icon等.
  • 布局型组件: 比如Grid, Layout布局等.
  • 导航型组件: 比如面包屑Breadcrumb, 下拉菜单Dropdown, 菜单Menu等.
  • 数据录入型组件: 比如form表单, Switch开关, Upload文件上传等.
  • 数据展示型组件: 比如Avator头像, Table表格, List列表等.
  • 反馈型组件: 比如Progress进度条, Drawer抽屉, Modal对话框等.
  • 其他业务类型

所以我们在设计组件系统的时候可以参考如上分类去设计,该分类也是antd, element, zend等主流UI库的分类方式.

如果对于react/vue组件设计原理不熟悉的,可以参考我的之前写的组件设计系列文章:

笔者已经将组件库发布到npm上了, 大家可以通过npm安装的方式体验组件.

正文

在开始组件设计之前希望大家对css3和js有一定的基础,并了解基本的react/vue语法.我们先看看实现后的组件效果:

1. 组件设计思路

按照之前笔者总结的组件设计原则,我们第一步是要确认需求. 一个警告提示(Alert)组件会有如下需求点:

  • 能控制Alert组件的样式
  • 能控制Alert组件的关闭按钮是否显示
  • 用户可以自己输入提示内容
  • 能控制关闭按钮的文本,或者自定义关闭按钮
  • 支持显示提示内容的辅助文本
  • 内置提供不同类型的警告提示样式,比如成功, 错误, 警告等
  • 关闭提示时能提供自定义事件

需求收集好之后,作为一个有追求的程序员, 会得出如下线框图:

对于react选手来说,如果没用typescript,建议大家都用PropTypes, 它是react内置的类型检测工具,我们可以直接在项目中导入. vue有自带的属性检测方式,这里就不一一介绍了.

通过以上需求分析, 我们发现实现一个Alert非常简单, 它属于反馈型组件,所以不会涉及到太多功能.接下来我们就来看看具体实现.

2. 基于react实现一个Alert组件

2.1. Alert组件框架设计

首先我们先根据需求将组件框架写好,这样后面写业务逻辑会更清晰:

1import classnames from 'classnames' 2import styles from './index.less' 3 4/** 5 * 警告提示组件 6 * @param {style} object 更改Alert样式 7 * @param {closable} bool 是否显示关闭按钮, 默认不显示 8 * @param {closeText} string|reactNode 自定义关闭按钮 9 * @param {message} string 警告提示内容 10 * @param {description} string 警告提示的辅助性文字 11 * @param {type} string 警告的类型 12 * @param {onClose} func 关闭时触发的事件 13 */ 14function Alert(props) { 15 const { 16 style, 17 closable, 18 closeText, 19 message, 20 description, 21 type, 22 onClose 23 } = props 24 25 return <div className={styles.xAlertWrap}> 26 <div className={styles.alertMes}>{ message }</div> 27 <div className={styles.alertDesc}>{ description }</div> 28 <span className={styles.closeBtn}>{ closeText ? closeText : 'x' }</span> 29 </div> 30} 31 32export default Alert

有了这个框架,我们来一步步往里面实现内容吧.

2.2 实现style, closeText,message, description, type

这几个功能在框架搭建好之后已经部分实现了,是因为他们都比较简单,不会牵扯到其他复杂逻辑.只需要对外暴露属性并使用属性即可. 具体实现如下:

1function Alert(props) { 2 const { 3 style, 4 closable, 5 closeText, 6 message, 7 description, 8 type, 9 onClose 10 } = props 11 12 return <div 13 className={classnames(styles.xAlertWrap, styles[type] || styles.warning)} 14 style={{ 15 ...style 16 }} 17 > 18 <div className={styles.alertMes}>{ message }</div> 19 <div className={styles.alertDesc}>{ description }</div> 20 <span className={styles.closeBtn}>{ closeText ? closeText : 'x' }</span> 21 </div> 22}

以上代码可以发现笔者采用了classnames这个第三方工具, 他可以组合我们的class以实现更灵活的配置. 对于type的实现,我的思路是提前预制好几种类型样式, 通过用户手动配置来匹配到对应的样式:

1.xAlertWrap { 2 box-sizing: border-box; 3 position: relative; 4 padding: 5px 12px; 5 margin-bottom: 16px; 6 border-radius: 3px; 7 &.success { 8 background-color: #f6ffed; 9 border: 1px solid #b7eb8f; 10 } 11 &.info { 12 background-color: #e6f7ff; 13 border: 1px solid #91d5ff; 14 } 15 &.error { 16 background-color: #fffbe6; 17 border: 1px solid #ffe58f; 18 } 19 &.warning { 20 background-color: #fff1f0; 21 border: 1px solid #ffa39e; 22 } 23}

2.3 实现closable和onClose

closable主要是用来让用户能手动关闭Alert,onClose是对外暴露的关闭时的方法, 因为没必要也不需要向外暴露属性来让Alert关闭, 所以最好的方式是在组件内部实现, 我们会通过useState这个钩子来处理,代码如下:

1function Alert(props) { 2 const { 3 style, 4 closable, 5 closeText, 6 message, 7 description, 8 type, 9 onClose 10 } = props 11 let [visible, setVisible] = useState(true) 12 13 const handleColse = () => { 14 setVisible(false) 15 onClose && onClose() 16 } 17 return visible ? 18 <div 19 className={classnames(styles.xAlertWrap, styles[type] || styles.warning)} 20 style={{ 21 opacity: visible ? '1' : '0', 22 ...style 23 }} 24 > 25 <div className={styles.alertMes}>{ message }</div> 26 <div className={styles.alertDesc}>{ description }</div> 27 { 28 !!closable && <span className={styles.closeBtn} onClick={handleColse}>{ closeText ? closeText : 'x' }</span> 29 } 30 </div> : null 31}

通过控制visible来控制Alert的出现和消失, 并且当点击关闭按钮时能调用外部暴露的onClose方法.

2.4 健壮性支持, 我们采用react提供的propTypes工具:

1import PropTypes from 'prop-types' 2// ... 3Alert.propTypes = { 4 style: PropTypes.object, 5 closable: PropTypes.bool, 6 closeText: PropTypes.oneOfType([ 7 PropTypes.string, 8 PropTypes.element 9 ]), 10 message: PropTypes.string, 11 description: PropTypes.string, 12 type: PropTypes.string, 13 onClose: PropTypes.func 14}

关于prop-types的使用官网上有很详细的案例,这里说一点就是oneOfType的用法, 它用来支持一个组件可能是多种类型中的一个. 组件完整css代码如下:

1.xAlertWrap { 2 box-sizing: border-box; 3 position: relative; 4 padding: 5px 12px; 5 margin-bottom: 16px; 6 border-radius: 3px; 7 &.success { 8 background-color: #f6ffed; 9 border: 1px solid #b7eb8f; 10 } 11 &.info { 12 background-color: #e6f7ff; 13 border: 1px solid #91d5ff; 14 } 15 &.error { 16 background-color: #fffbe6; 17 border: 1px solid #ffe58f; 18 } 19 &.warning { 20 background-color: #fff1f0; 21 border: 1px solid #ffa39e; 22 } 23 24 .alertMes { 25 margin-bottom:5px; 26 color: rgba(0, 0, 0, 0.85); 27 font-size: 14px; 28 line-height: 1.5em; 29 } 30 .alertDesc { 31 color: rgba(0, 0, 0, 0.65); 32 font-size: 14px; 33 line-height: 1.5em; 34 word-break: break-all; 35 } 36 .closeBtn { 37 position: absolute; 38 right: 8px; 39 top: 5px; 40 color: rgba(0, 0, 0, 0.4); 41 cursor: pointer; 42 } 43}

通过以上步骤, 一个健壮的的Alert组件就完成了,关于代码中的css module和classnames的使用大家可以自己去官网学习,非常简单.如果不懂的可以在评论区提问,笔者看到后会第一时间解答.

2.5 使用Alert组件

我们可以通过如下方式使用它:

1<Alert message="温馨提示,你忘带口罩了" /> 2<Alert message="温馨提示,你注册成功" type="success" /> 3<Alert message="错误提示,你没洗手了" type="error" /> 4<Alert message="提示: 我们开始吧" type="info" /> 5<Alert message="提示: 我可以关闭了" type="info" closable onClose={() => { alert(111) }} /> 6<Alert message="注册成功" description="你在本网站已经注册成功,谢谢您的支持和反馈,多交流真正的技术吧" closable type="success" />

笔者已经将实现过的组件发布到npm上了,大家如果感兴趣可以直接用npm安装后使用,方式如下:

1npm i @alex_xu/xui 2 3// 导入xui 4import { 5 Button, 6 Skeleton, 7 Empty, 8 Progress, 9 Tag, 10 Switch, 11 Drawer, 12 Badge, 13 Alert 14} from '@alex_xu/xui'

该组件库支持按需导入,我们只需要在项目里配置babel-plugin-import即可,具体配置如下:

1// .babelrc 2"plugins": [ 3 ["import", { "libraryName": "@alex_xu/xui", "style": true }] 4]

npm库截图如下:

最后

后续笔者将会继续实现

  • modal(模态窗),
  • badge(徽标),
  • table(表格),
  • tooltip(工具提示条),
  • Skeleton(骨架屏),
  • Message(全局提示),
  • form(form表单),
  • switch(开关),
  • 日期/日历,
  • 二维码识别器组件

等组件, 来复盘笔者多年的组件化之旅.

如果想获取组件设计系列完整源码, 或者想学习更多H5游戏, webpacknodegulpcss3javascriptnodeJScanvas数据可视化等前端知识和实战,欢迎在公号《趣谈前端》加入我们的技术群一起学习讨论,共同探索前端的边界。

更多推荐

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )