如何用react实现一款全局Message

1,465 阅读2分钟

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

TIP 👉 千磨万击还坚劲,任尔东西南北风。——郑燮《竹石》

前言

Web Component是前端界一直非常热衷的一个领域,用第三方组件化的框架去实现的话,你需要依赖框架本身很多东西,很多时候我们只是简单的几个组件,不是很大,也不是很多,所以为了保证组件的`轻量,简单`,其实这个时候我们并不想采用第三方的框架。

Message 全局提示

import

import Message from '@/components/Message/Message';

Props

1. visible

  • 类型:bool
  • 默认值:false
  • 说明:是否可见

2. type

  • 类型:string
  • 默认值:basic
  • 说明:提示类型

3. content

  • 类型:string|ReactNode
  • 默认值:无
  • 说明:提示内容

4. duration

  • 类型:number
  • 默认值:3000
  • 说明:自动关闭的延时,单位为毫秒

5. top

  • 类型:number
  • 默认值:18
  • 说明:消息距离顶部的位置

让我们来写代码实现message.js

import React from 'react';
import PropTypes from 'prop-types';
const classNames = require('classnames');
import './message.scss';

/**
 * Message 全局提示
 */
class Message extends React.Component {
    // 入参类型检查
    static propTypes = {
        // 是否显示
        visible: PropTypes.bool,
        // 类型
        type: PropTypes.string,
        // 提示内容
        content: PropTypes.oneOfType([
            PropTypes.string,
            PropTypes.node]
        ),
        // 自动关闭的延时,单位为毫秒
        duration: PropTypes.number,
        // 提示消息距离顶部的位置
        top: PropTypes.number,
    };

    // 入参默认值
    static defaultProps = {
        visible: false,
        type: 'basic',
        duration: 3000,
        top: 18
    };

    constructor(props) {
        super(props);
        this.removeMessage = this.removeMessage.bind(this);
    }

    componentWillMount() {
        this.removeMessage();
    }

    componentWillReceiveProps(nextProps) {
        const { visible } = nextProps;
        this.setState({
            visible: visible,
        });
        if (visible) {
            this.removeMessage();
        }
    }
    
    removeMessage() {
        const { duration } = this.props;
        if (this.timer) {
            clearTimeout(this.timer);
        }
        this.timer = setTimeout(() => {
            this.setState({
                visible: false,
            });
        }, duration);
    }

    render() {
        const {visible, type, content, top} = this.props;

        var iconClass1 = classNames('icon', {
            [`icon-${type}`]: type
        });

        let iconClass2 = '';
        switch (type) {
            case 'success':
                iconClass2 = 'icon-jieguoye';
                break;
            case 'error':
                iconClass2 = 'icon-guanbishibaixianxing';
                break;
            case 'warning':
                iconClass2 = 'icon-xinxi-xianxing';
                break;
            case 'basic':    
            default:
                iconClass2 = 'icon-xinxi-xianxing';
                break;
        }

        if(!visible) return null;

        return (
            <div className="message" style={{top: parseFloat(top)+'px'}}>
                <div className={`message-box ${type}`}>
                    {
                        <p>
                            <i className={`${iconClass1} ${iconClass2}`}></i>
                            {content}
                        </p>
                    }
                </div>
            </div>
        )
    }
}
export default Message;

样式message.scsss

@import '../../scss/util.scss';

.message {
    position: fixed;
    top: 16px;
    right: 0;
    z-index: 1000;  
    width: 100%;
    text-align: center;
}

.message-box {
    display: inline-block;
    margin: 0 auto;   
    font-size: 14px;
    color: #fff;
    text-align: left;    
    p {
        padding: 8px 20px;
        text-align: center;
        .icon{
            margin-right: 10px;
        }
    }
    &.basic {
        background:rgba(0,153,255,0.8);
        box-shadow: 0 4px 12px rgba(0, 0, 0, .15);
    }
    &.success {
        background:rgba(44,215,170,0.8);
        box-shadow: 0 4px 12px rgba(0, 0, 0, .15);
    }
    &.error {
        background:rgba(242,39,53,0.8);
        box-shadow: 0 4px 12px rgba(0, 0, 0, .15);
    }
    &.warning {
        background:rgba(248,172,48,0.8);
        box-shadow: 0 4px 12px rgba(0, 0, 0, .15);
    }
}

「欢迎在评论区讨论」

希望看完的朋友可以给个赞,鼓励一下