精通React/Vue系列之实现一个全局提示(Message)组件
2020/2/20 11:26:42
本文主要是介绍精通React/Vue系列之实现一个全局提示(Message)组件,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
本文是笔者写组件设计的第十一篇文章, 今天带大家实现一个同样比较特殊的组件——全局提示(Message)组件。 我们看到的组件效果可能是这样的:
由于全局提示组件的设计原理和笔者上一篇写的精通React/Vue系列之手把手带你实现一个功能强大的通知提醒框(Notification)是类似的,区别主要是布局和配置参数,所以说细节和实现原理部分就不在这篇文章介绍了,本文主要介绍设计思路和设计的方法。基础组件库主要按以下分类来划分:
- 通用型组件: 比如Button, Icon等.
- 布局型组件: 比如Grid, Layout布局等.
- 导航型组件: 比如面包屑Breadcrumb, 下拉菜单Dropdown, 菜单Menu等.
- 数据录入型组件: 比如form表单, Switch开关, Upload文件上传等.
- 数据展示型组件: 比如Avator头像, Table表格, List列表等.
- 反馈型组件: 比如Progress进度条, Drawer抽屉, Modal对话框等.
- 其他业务类型
熟悉以上分类法是设计任何组件系统的前提,不管你是从零到一开发前端团队的UI库,还是基于已有组件库二次开发业务组件,以上分类法则同样适用。
本文将会使用React来开发该组件,也会使用到Javascript中常用的一些设计模式,比如单例模式,但是不管你使用什么框架来实现,原理都是通用的,如果感兴趣的朋友可以用vue也实现一下。如果对设计模式不是很了解,可以移步:
15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码).
正文
在开始组件设计之前希望大家对css3和js有一定的基础,并了解基本的react/vue语法.我们先来解构一下Message组件, 一个Message分为以下几个部分:
每一个区块都可以自定义配置, 也可以组合其他组件.我们还可以配置全局提示出现在顶部的偏移量,类似于antd的组件一样。并且我们都知道,antd或者element这种组件库,会自带一些主题状态,来提高用户的使用效率,比如会有success(成功状态),warning(警告状态),error(错误状态),info(通知状态)等,那么我们自己实现的全局提示(Message)组件也因该具备这些功能。以下是笔者使用React实现后的Message组件效果:
接下来我们来看看通知提醒框(Message)的具体设计思路。
1. Message组件设计思路
按照之前笔者总结的组件设计原则,我们第一步是要确认需求. 通知提醒框(Message)组件一般会有如下需求点:
- 能控制Message自动关闭的时间
- 能配置Message渲染节点的输出位置
- 能自定义关闭图标
- 可以手动选择全局提示类型
- 能自定义全局提示的偏移量
- 能设置全局提示的信息文本
- 能自定义全局提示的Icon
- 全局提示点击时提供回调函数
- 全局提示关闭时提供回调函数
- 能手动销毁通知框
需求收集好之后,作为一个有追求的程序员, 会得出如下线框图:
具体的设计细节可以参考我的上一篇Notification组件设计的文章。2. 基于react实现一个全局提示(Message)组件
组件的核心部分我们还是采用React Notification的模式。
2.1 搭建通知提醒框(Notification)的基本骨架
首先按照笔者的代码风格,一般会考虑组件设计的框架,然后再一步步往里面填充内容和逻辑。通过这种渐进式的设计思路,能让我们逻辑更严谨,更清晰。具体代码如下:
import Notification from 'rc-notification' import './index.less' const xMessage = (function() { let message = null /** * notice类型弹窗 * @param {config} object 提示框配置属性 * @param {type} string 提示窗类型 * @param {btn} ReactNode 自定义关闭按钮 * @param {className} string 自定义 CSS class * @param {duration} number 默认 4.5 秒后自动关闭,配置为 null 则不自动关闭 * @param {getContainer} HTMLNode 配置渲染节点的输出位置 * @param {icon} ReactNode 自定义图标 * @param {key} string 当前提示唯一标志 * @param {content} string|ReactNode 提示标题,必选 * @param {onClose} func 点击默认关闭按钮时触发的回调函数 * @param {onClick} func 点击提示时触发的回调函数 * @param {top} number 消息从顶部弹出时,距离顶部的位置,单位像素 * @param {closeIcon} ReactNode 自定义关闭图标 */ const pop = (config) => { const { type, className, duration = 4.5, getContainer = () => document.body, icon, key, content, onClose, onClick, top, closable = true, closeIcon } = config message.notice({ content: <div className={classnames('xMessage', className )}> <div className={classnames('iconWrap', type)}> <Icon type={iconType[type]} /> </div> <div className="xNoticeTit"> { content } </div> </div>, key, closable, getContainer, onClose() { onClose && onClose() }, onClick() { onClick && onClick() }, closeIcon, duration, style: { top } }) } /** * 提示提示组件, 全局参数 * @param {duration} number 默认自动关闭延时,单位秒 * @param {getContainer} HTMLNode 配置渲染节点的输出位置,默认document.body * @param {closeIcon} HTMLNode 自定义关闭图标 */ const config = (config) => {} const remove = (key) => {} const destroy = () => {} if(message) { return { config, pop, remove, destroy } } // 如果为创建实例,则创建默认实例 Notification.newInstance({}, (notice) => message = notice) return { config, pop, remove, destroy } })() export default xMessage 复制代码
首先我们根据需求把属性罗列出来, 通过分析我们因该对外提供四个接口供开发者使用,分别为:
- config —— Message全局配置,用来控制全局的偏移量,样式,渲染容器等;
- pop —— 用来创建全局提示实例的方法,同时可以控制实例的属性
- remove —— 用来删除指定实例
- destroy —— 用来销毁全局的Message
首先我们来实现一下config:
const config = (config) => { const { duration, getContainer, closeIcon } = config Notification.newInstance({ getContainer: getContainer, duration: duration || 4.5, closeIcon }, (notice) => message = notice) } 复制代码
当然我们还可以根据自己的需求去自定义扩展。
pop方法的实现:
const pop = (config) => { const { type, className, duration = 4.5, getContainer = () => document.body, icon, key, content, onClose, onClick, top, closable = true, closeIcon } = config message.notice({ content: <div className={classnames('xMessage', className )}> { (icon || ['info', 'success', 'error', 'warning'].indexOf(type) > -1) && <div className={classnames('iconWrap', type)}> { icon ? icon : <Icon type={iconType[type]} /> } </div> } <div className="xNoticeTit"> { content } </div> </div>, key, closable, getContainer, onClose() { onClose && onClose() }, onClick() { onClick && onClick() }, closeIcon, duration, style: { top } }) } 复制代码
该方法主要用来自定义创建全局消息的实例,我们可以这么调用:
xNotification.pop({type: 'success', content: '你的请求被审批通过啦!'}) 复制代码
实际效果如下:
antd同样的方式会这么调用:// antd Notification.info({//...}) 复制代码
笔者之所以会这么做是因为info,success,warning这样的状态其实dom结构完全可以复用,所以通过配置方式可以极大的减少冗余代码。
remove和destroy方法都比较简单,我们直接上代码:
const remove = (key) => { message.removeNotice(key) } const destroy = () => { message.destroy() } 复制代码
由上可以看出他们的实现都是基于message实例自带的API。
2.2 实现通知框类型type和自定义icon
首先我们先定义一个类型和icon的映射关系:
const iconType = { success: 'FaRegCheckCircle', warning: 'FaRegMeh', info: 'FaRegLightbulb', error: 'FaRegTimesCircle' } 复制代码
这四种类型对应着不同的icon图标类型,那么我们就可以根据用户传入的类型来展示不同icon图标了:
<div className={classnames('iconWrap', type)}> <Icon type={iconType[type]} /> </div> 复制代码
不过我们还需要考虑的一点就是如果用户传入了自定义的icon,我们理论上应该展示自定义icon,所以type因该和icon这两个属性是有联系的。还有一种情况就是如果用户即没有配置type,有没有传入icon,那么实际上是不需要显示icon的,综合考虑之后我们的代码如下:
{ (icon || ['info', 'success', 'error', 'warning'].indexOf(type) > -1) && <div className={classnames('iconWrap', type)}> { icon ? icon : <Icon type={iconType[type]} /> } </div> } 复制代码
实现效果如下图:
通过以上步骤, 全局提示(Message)组件就完成了.实现方式和Notification组件有很多相似点,如果不懂的可以在评论区提问,笔者看到后会第一时间解答.2.3 使用全局提示(Message)组件
我们可以通过如下方式使用它:
<Button type="warning" onClick={ () => { message.pop({ type: 'error', content: '趣谈前端学习打卡' }) } }>错误信息通知(error)</Button> 复制代码
配置全局属性:
import { message } from '@alex_xu/xui' message.config({ duration: 6 }) 复制代码
笔者已经将实现过的组件发布到npm上了,大家如果感兴趣可以直接用npm安装后使用,方式如下:
npm i @alex_xu/xui // 导入xui import { Button, Skeleton, Empty, Progress, Message, Tag, Switch, Drawer, Badge, Alert } from '@alex_xu/xui' 复制代码
该组件库支持按需导入,我们只需要在项目里配置babel-plugin-import即可,具体配置如下:
// .babelrc "plugins": [ ["import", { "libraryName": "@alex_xu/xui", "style": true }] ] 复制代码
npm库截图如下:
最后
后续笔者将会继续实现
- table(表格),
- tooltip(工具提示条),
- Skeleton(骨架屏),
- form(form表单),
- switch(开关),
- 日期/日历,
- 二维码识别器组件
等组件, 来复盘笔者多年的组件化之旅.
如果对于react/vue组件设计原理不熟悉的,可以参考我的之前写的组件设计系列文章:
- 精通React/Vue系列之手把手带你实现一个功能强大的通知提醒框(Notification)
- 手摸手实现一个轻量级可扩展的模态框(Modal)组件
- 《精通react/vue组件设计》之配合React Portals实现一个功能强大的抽屉(Drawer)组件
- 《精通react/vue组件设计》之5分钟实现一个Tag(标签)组件和Empty(空状态)组件
- 《精通react/vue组件设计》之用纯css打造类materialUI的按钮点击动画并封装成react组件
- 《精通react/vue组件设计》之快速实现一个可定制的进度条组件
- 《精通react/vue组件设计》之基于jsoneditor二次封装一个可实时预览的json编辑器组件(react版)
笔者已经将组件库发布到npm上了, 大家可以通过npm安装的方式体验组件.
如果想获取组件设计系列完整源码, 或者想学习更多H5游戏, webpack,node,gulp,css3,javascript,nodeJS,canvas数据可视化等前端知识和实战,欢迎在公号《趣谈前端》加入我们的技术群一起学习讨论,共同探索前端的边界。
更多推荐
- 2年vue项目实战经验汇总
- 15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码)
- 2019年,盘点一些我出过的前端面试题以及对求职者的建议
- 一张图教你快速玩转vue-cli3
- vue高级进阶系列——用typescript玩转vue和vuex
- 《前端实战总结》之使用纯css实现网站换肤和焦点图切换动画
- 《前端实战总结》之使用CSS3实现酷炫的3D旋转透视
- 《前端实战总结》之使用pace.js为你的网站添加加载进度条
- 《前端实战总结》之设计模式的应用——备忘录模式
- 《前端实战总结》之使用postMessage实现可插拔的跨域聊天机器人
- 《前端实战总结》之变量提升,函数声明提升及变量作用域详解
- 《前端实战总结》如何在不刷新页面的情况下改变URL
这篇关于精通React/Vue系列之实现一个全局提示(Message)组件的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-24Vue CLI多环境配置学习:从入门到实践
- 2024-11-24Vue CLI多环境配置学习:新手入门教程
- 2024-11-24Vue CLI学习:初学者指南
- 2024-11-24Vue CLI学习:从入门到上手的简单教程
- 2024-11-24Vue3+Vite学习:从零开始的前端开发之旅
- 2024-11-24Vue3阿里系UI组件学习入门教程
- 2024-11-24Vue3的阿里系UI组件学习入门指南
- 2024-11-24Vue3公共组件学习:新手入门教程
- 2024-11-24Vue3公共组件学习入门指南
- 2024-11-24vue3核心功能响应式变量学习