js 实现全局消息提示

2,381 阅读1分钟

前言

之前项目中有使用Ant Design组件库进行开发,觉得message全局提示的功能挺有意思的,就花了点时研究了一下。支持五种提示,分别是success,error,info,warning,loading。用户可以主动移除,也可设置延时自动移除。是一种不打断用户操作的轻量级提示方式。快来看一下如何实现的吧。

页面结构

<div class="overlay">
    <ul class="message-list"></ul>
</div>

样式

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
                
.overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000;
    /* 元素永远不会成为鼠标事件的target */
    pointer-events: none;
}

.message-list {
    position: fixed;
    top: 30px;
    left: 0;
    right: 0;
    list-style: none;
}

.message-item {
    display: flex;
    justify-content: center;
    padding: 8px;
}

.message-item div {
    display: flex;
    align-items: center;
    padding: 10px 16px;
    background: #FFF;
    border-radius: 2px;
    box-shadow: 0 3px 6px -4px rgb(0 0 0 / 12%), 0 6px 16px 0 rgb(0 0 0 / 8%), 0 9px 28px 8px rgb(0 0 0 / 5%);
}

.message-item .icon {
    width: 16px;
    height: 16px;
    margin-right: 10px;
}

/* loading旋转动画 */
.message-item .icon.loading {
    animation: loading 1s linear infinite;
}

@keyframes loading {
    0% {
        transform: rotate(0deg);
    }

    100% {
        transform: rotate(360deg);
    }
}

.message-item div span {
    font-size: 14px;
    line-height: 20px;
}

.fade-in {
    animation: fadeIn .3s ease forwards;
}

/* 淡入动画 */
@keyframes fadeIn {
    0% {
        opacity: 0;
        transform: translateY(-100%);
    }

    100% {
        opacity: 1;
        transform: translateY(0);
    }
}

/* 淡出动画 */
.fade-out {
    animation: fadeOut .3s ease forwards;
}

@keyframes fadeOut {
    0% {
        opacity: 1;
        transform: translateY(0);
    }

    100% {
        opacity: 0;
        transform: translateY(-100%);
    }
}

代码

/* 构造函数 */
function Message() { }
/* 用于移除message */
Message.id = 0;
/**
 * 创建全局提示
 * @param {string} content 提示内容
 * @param {number} duration 持续时间
 * @param {string} type 提示类型
 */
Message.prototype.create = function (content, duration, type) {
    // svg太长,此处省略
    const icon = {
        success: '<svg class="icon success">...</svg>',
        error: '<svg class="icon error">...</svg>',
        info: '<svg class="icon info">...</svg>',
        warning: '<svg class="icon warning">...</svg>',
        loading: '<svg class="icon loading">...</svg>'
    }
    const html = `
        <li class="message-item fade-in" data-id="${Message.id}">
            <div>
                ${icon[type]}
                <span>${content}</span>
            </div>
        </li>`;
    ul.insertAdjacentHTML('beforeend', html);
    Message.id++;
    const lis = document.querySelectorAll('li.message-item');
    const length = lis.length;
    const lastLi = lis[length - 1];
    // 延时移除
    lastLi._timeout = setTimeout(function () {
        lastLi.classList.remove('fade-in');
        lastLi.classList.add('fade-out');
        lastLi.addEventListener('animationend', function (e) {
            this.remove();
        });
    }, duration);
    // 最多显示7条
    if (length > 7) {
        clearTimeout(lis[0]._timeout);
        lis[0].remove();
    }
}
Message.prototype.success = function (content, duration = 3000) {
    this.create(content, duration, 'success');
    return Message.id;
}
Message.prototype.error = function (content, duration = 3000) {
    this.create(content, duration, 'error');
    return Message.id;
}
Message.prototype.warning = function (content, duration = 3000) {
    this.create(content, duration, 'warning');
    return Message.id;
}
Message.prototype.info = function (content, duration = 3000) {
    this.create(content, duration, 'info');
    return Message.id;
}
Message.prototype.loading = function (content, duration = 3000) {
    this.create(content, duration, 'loading');
    return Message.id;
}
Message.prototype.remove = function (id) {
    const li = document.querySelector(`li.message-item[data-id="${id}"]`);
    clearTimeout(li._timeout);
    li.remove();
}

// 调用
const message = new Message();
const id = message.success('This is a message of success');
// 移除
message.remove(id);

Demo:jsdemo.codeman.top/html/messag…