内容简介:很多项目中需要实现app中常见的提示效果Toast。这个效果看似简单,实现起来也容易,为了方便,将它封装成npm组件,方便后续使用。 这里也是抛砖引玉,可以查看项目地址一起学习Notification是个容器,里面有一个notice数组。 然后render的时候,循环notices生成一段DOM节点,放到自己的div中。 同时,其还提供一个向notices中添加notice的方法(add)和根据key,在notices中删除notice的方法(remove)。 最后关键的地方,定义一个reRwrite方法,
很多项目中需要实现app中常见的提示效果Toast。这个效果看似简单,实现起来也容易,为了方便,将它封装成npm组件,方便后续使用。 这里也是抛砖引玉,可以查看项目地址一起学习 react-comment-toast
使用方法
import Toast from "react-common-toast"; Toast.info("xxx"); Toast.info("xxx",duration,onClose); 复制代码
组件拆分
- 首先是支持多个提示,不同提示定制化也可以不同。取名为Notice。
- Notice外面还有个容器组件,用来装载Notice并且,暴露一些方法给Toast,起名Notification,是一个单例。
- 最后就是Toast组件,负责直接生成不同的Notice,或者销毁Notification。但是其实Toast只是个对象,而不是真正意义的组件。
Notification
Notification是个容器,里面有一个notice数组。 然后render的时候,循环notices生成一段DOM节点,放到自己的div中。 同时,其还提供一个向notices中添加notice的方法(add)和根据key,在notices中删除notice的方法(remove)。 最后关键的地方,定义一个reRwrite方法,该方法接受一些参数,动态的向DOM中插入一个div,然后再向这个div中插入Notification,最后返回一个含有几个操作这个Notification的方法的对象。(这就是动态实现插入DOM的关键)
// Notification是Notice父组件,容器 // 是动态插入和删除DOM节点的核心 // 同时也向上暴露给Toast重写改变自己的方法 import React from "react"; import ReactDOM from "react-dom"; import Notice from "./Notice"; import "./toast.css"; // 统计notice总数 防止重复 let noticeNumber = 0; // 生成唯一的id const getUuid = () => { return "notification-" + new Date().getTime() + "-" + noticeNumber++; }; export default class Notification extends React.Component { constructor(props) { super(props); this.state = { notices: [], // 存储当前有的notices hasMask: true // 是否显示蒙版 }; } add(notice) { // 添加notice // 创造一个不重复的key const { notices } = this.state; const key = notice.key ? notice.key : (notice.key = getUuid()); const mask = notice.mask ? notice.mask : false; const temp = notices.filter(item => item.key === key).length; if (!temp) { // 不存在重复的 添加 notices.push(notice); this.setState({ notices: notices, hasMask: mask }); } } remove(key) { // 根据key删除对应 this.setState(previousState => { return { notices: previousState.notices.filter(notice => notice.key !== key) }; }); } getNoticeDOM() { const _this = this; const { notices } = this.state; let result = []; notices.map(notice => { // 每个Notice onClose的时候 删除掉notices中对应key的notice const closeCallback = () => { _this.remove(notice.key); // 如果有用户传入的onClose 执行 if (notice.onClose) notice.onClose(); }; result.push( <Notice key={notice.key} {...notice} onClose={closeCallback} /> ); }); return result; } getMaskDOM() { const { notices, hasMask } = this.state; // notices为空的时候 不显示蒙版 // 始终只有一个蒙版 if (notices.length > 0 && hasMask == true) return <div className="tips-mask" />; } render() { const noticesDOM = this.getNoticeDOM(); //暂时没有配置蒙版 const maskDOM = this.getMaskDOM(); return ( <div> {/*{maskDOM}*/} {noticesDOM} </div> ); } } // Notification增加一个重写方法 // 该方法方便Notification组件动态添加到页面中和重写 Notification.reWrite = properties => { const { ...props } = properties || {}; let div = document.createElement("div"); document.body.appendChild(div); const notification = ReactDOM.render(<Notification {...props} />, div); return { notice(noticeProps) { notification.add(noticeProps); }, removeNotice(key) { notification.remove(key); }, destroy() { ReactDOM.unmountComponentAtNode(div); document.body.removeChild(div); }, component: notification }; }; 复制代码
Notice
主要是负责接受一些参数,duration,icon,content等等
// Notice是Toast最底层组件 // 每个toast的小框框其实都是一个Notice // Notice核心就是组件初始化的时候 生成一个定时器 // 根据输入的时间 加载一个动画 然后执行输入的回调 // Notice的显示和隐藏收到父组件Notification的绝对控制 import React from "react"; import classNames from "classnames"; import { PropTypes } from "prop-types"; export default class Notice extends React.Component { constructor(props) { super(props); this.state = { shouldClose: false // 是否开启关闭动画 }; } componentDidMount() { if (this.props.duration > 0) { this.closeTimer = setTimeout(() => { this.close(); }, this.props.duration - 300); // 减掉消失动画300毫秒 } } componentWillUnmount() { // 当有意外关闭的时候 清掉定时器 this.clearCloseTimer(); } clearCloseTimer() { if (this.closeTimer) { clearTimeout(this.closeTimer); this.closeTimer = null; } } close() { // 关闭的时候 应该先清掉倒数定时器 // 然后开启过场动画 // 等待动画结束 执行回调 this.clearCloseTimer(); const _this = this; _this.setState({ shouldClose: true }); this.timer = setTimeout(() => { if (this.props.onClose) { this.props.onClose(); } clearTimeout(_this.timer); }, 300); } render() { const { shouldClose } = this.state; return <div className={classNames({ leave: shouldClose })}> {this.props.content} </div> } } Notice.propTypes = { duration: PropTypes.number, // Notice显示时间 content: PropTypes.any, // Notice显示的内容 onClose: PropTypes.func // 显示结束回调 }; Notice.defaultProps = { duration: 3000 }; 复制代码
Toast
Toast首先就是要利用Notification.reWrite初始化一个newNotification,并且保持这个Notification为单例。 然后封装一个notice方法,动态的改变这个newNotification。 最后封装几个常用notice方法暴露出去。
import React from "react"; import classNames from "classnames"; import Notification from "./Notification"; // Toast组件比较特殊 // 因为<Toast />不会被直接渲染在DOM中 // 而是动态插入页面中 // Toast组件核心就是通过Notification暴露的重写方法 动态改变Notification let newNotification; // 获得一个Notification const getNewNotification = () => { // 单例 保持页面始终只有一个Notification if (!newNotification) { newNotification = Notification.reWrite(); } return newNotification; }; // notice方法实际上就是集合参数 完成对Notification的改变 const notice = (content, type, duration = 3000, onClose, mask = true) => { if (!content) return; // content = content.toString(); let notificationInstance = getNewNotification(); notificationInstance.notice({ duration, mask: mask, content: ( <div className={classNames(["tips-notice-box"])}> <div className={classNames([ "tips-notice-content", { info: type === "info" }, { success: type === "success" }, { warning: type === "warning" }, { error: type === "error" } ])} > {content} </div> </div> ), onClose: () => { if (onClose) onClose(); } }); }; export default { show(content, duration, icon, mask, onClose) { return notice(content, undefined, icon, duration, onClose, mask); }, info(content, duration, icon, mask, onClose) { return notice(content, "info", icon, duration, onClose, mask); }, success(content, duration, icon, mask, onClose) { return notice(content, "success", icon, duration, onClose, mask); }, warning(content, duration, icon, mask, onClose) { return notice(content, "warning", icon, duration, onClose, mask); }, error(content, duration, icon, mask, onClose) { return notice(content, "error", icon, duration, onClose, mask); }, hide() { if (newNotification) { newNotification.destroy(); newNotification = null; } } }; 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- php如何实现session,自己实现session,laravel如何实现session
- AOP如何实现及实现原理
- webpack 实现 HMR 及其实现原理
- Docker实现原理之 - OverlayFS实现原理
- 为什么实现 .NET 的 ICollection 集合时需要实现 SyncRoot 属性?如何正确实现这个属性?
- 自己实现集合框架(十):顺序栈的实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。