内容简介:Toast组件可以被分为三个部分,分别为:项目目录结构如下:为了便于理解,这里从外部的toast部分开始实现。
- Toast不需要同页面一起被渲染,而是根据需要被随时调用。
- Toast是一个轻量级的提示组件,它的提示不会打断用户操作,并且会在提示的一段时间后自动关闭。
- Toast需要提供几种不同的消息类型以适应不同的使用场景。
- Toast的方法必须足够简洁,以避免不必要的代码冗余。
最终效果:
调用示例
Toast.info('普通提示') Toast.success('成功提示', 3000) Toast.warning('警告提示', 1000) Toast.error('错误提示', 2000, () => { Toast.info('哈哈') }) const hideLoading = Toast.loading('加载中...', 0, () => { Toast.success('加载完成') }) setTimeout(hideLoading, 2000) 复制代码
组件实现
Toast组件可以被分为三个部分,分别为:
- notice.js:Notice。无状态组件,只负责根据父组件传递的参数渲染为对应提示信息的组件,也就是用户最终看到的提示框。
- notification.js:Notification。Notice组件的容器,用于保存页面中存在的Notice组件,并提供Notice组件的添加和移除方法。
- toast.js:控制最终对外暴露的接口,根据外界传递的信息调用Notification组件的添加方法以向页面中添加提示信息组件。
项目目录结构如下:
├── toast │ ├── icons.js │ ├── index.js │ ├── notice.js │ ├── notification.js │ ├── toast.css │ ├── toast.js 复制代码
为了便于理解,这里从外部的toast部分开始实现。
toast.js
因为页面中没有Toast组件相关的元素,为了在页面中插入提示信息,即Notice组件,需要首先将Notice组件的容器Notification组件插入到页面中。这里定义一个createNotification函数,用于在页面中渲染Notification组件,并保留addNotice与destroy函数。
function createNotification() { const div = document.createElement('div') document.body.appendChild(div) const notification = ReactDOM.render(<Notification />, div) return { addNotice(notice) { return notification.addNotice(notice) }, destroy() { ReactDOM.unmountComponentAtNode(div) document.body.removeChild(div) } } } 复制代码
接着定义一个全局的notification变量用于保存createNotification返回的对象。并定义对外暴露的函数,这些函数被调用时就会将参数传递回Notification组件。因为一个页面中只需要存在一个Notification组件,所以每次调用函数时只需要判断当前notification对象是否存在即可,无需重复创建。
let notification const notice = (type, content, duration = 2000, onClose) => { if (!notification) notification = createNotification() return notification.addNotice({ type, content, duration, onClose }) } export default { info(content, duration, onClose) { return notice('info', content, duration, onClose) }, success(content, duration, onClose) { return notice('success', content, duration, onClose) }, warning(content, duration, onClose) { return notice('warning', content, duration, onClose) }, error(content, duration, onClose) { return notice('error', content, duration, onClose) }, loading(content, duration = 0, onClose) { return notice('loading', content, duration, onClose) } } 复制代码
notification.js
这样外部工作就已经完成,接着需要完成Notification组件内部的实现。首先Notification组件的state属性中有一个notices属性,用于保存当前页面中存在的Notice的信息。并且Notification组件拥有addNotice和removeNotice两个方法,用于向notices中添加和移除Notice的信息(下文简写为notice)。
添加notice时,需要使用getNoticeKey方法为这个notice添加唯一的key值,再将其添加到notices中。并根据参数提供的duration,设置定时器以在到达时间后将其自动关闭,这里规定若duration的值小于等于0则消息不会自动关闭,而是一直显示。最后方法返回移除自身notice的方法给调用者,以便其根据需要立即关闭这条提示。
调用removeNotice方法时,会根据传递的key的值遍历notices,如果找到结果,就触发其或调函数并从notices中移除。
最后就是遍历notices数组并将notice属性传递给Notice组件以完成渲染,这里使用react-transition-group实现组件的进场与出场动画。
(注:关于页面中同时存在多条提示时的显示问题,本文中采用的方案时直接将后一条提示替换掉前一条消息,所以代码中添加notice直接写成了 notices[0] = notice 而非 notices.push(notice), 如果想要页面中多条提示共存的效果可以自行修改。)
class Notification extends Component { constructor() { super() this.transitionTime = 300 this.state = { notices: [] } this.removeNotice = this.removeNotice.bind(this) } getNoticeKey() { const { notices } = this.state return `notice-${new Date().getTime()}-${notices.length}` } addNotice(notice) { const { notices } = this.state notice.key = this.getNoticeKey() if (notices.every(item => item.key !== notice.key)) { notices[0] = notice this.setState({ notices }) if (notice.duration > 0) { setTimeout(() => { this.removeNotice(notice.key) }, notice.duration) } } return () => { this.removeNotice(notice.key) } } removeNotice(key) { this.setState(previousState => ({ notices: previousState.notices.filter((notice) => { if (notice.key === key) { if (notice.onClose) notice.onClose() return false } return true }) })) } render() { const { notices } = this.state return ( <TransitionGroup className="toast-notification"> { notices.map(notice => ( <CSSTransition key={notice.key} classNames="toast-notice-wrapper notice" timeout={this.transitionTime} > <Notice {...notice} /> </CSSTransition> )) } </TransitionGroup> ) } } 复制代码
notice.js
最后剩下的Notice组件就很简单了,只需要根据Notification组件传递的信息输入最终的内容即可。可以自行发挥设计样式。
class Notice extends Component { render() { const icons = { info: 'icon-info-circle-fill', success: 'icon-check-circle-fill', warning: 'icon-warning-circle-fill', error: 'icon-close-circle-fill', loading: 'icon-loading' } const { type, content } = this.props return ( <div className={`toast-notice ${type}`}> <svg className="icon" aria-hidden="true"> <use xlinkHref={`#${icons[type]}`} /> </svg> <span>{content}</span> </div> ) } } 复制代码
结语
以上所述就是小编给大家介绍的《实现基于React的全局提示组件Toast》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Serverless 组件开发尝试:全局变量组件和单独部署组件
- Vue组件之全局注册
- 基于AOP的一种RecyclerView复杂楼层开发框架,支持组件化,全局楼层打通,MVP等高拓展性功能
- 全局变量,静态全局变量,局部变量,静态局部变量
- Thrift RPC 系列教程(2)——全局变量&全局常量
- 全局角度出发讨论敏捷
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java 8函数式编程
[英] Richard Warburton / 王群锋 / 人民邮电出版社 / 2015-3 / 39.00元
通过每一章的练习快速掌握Java 8中的Lambda表达式 分析流、高级集合和其他Java 8类库的改进 利用多核CPU提高数据并发的性能 将现有代码库和库代码Lambda化 学习Lambda表达式单元测试和调试的实践解决方案 用Lambda表达式实现面向对象编程的SOLID原则 编写能有效执行消息传送和非阻塞I/O的并发应用一起来看看 《Java 8函数式编程》 这本书的介绍吧!