原生js构建消息提示框

思路

原生js构建消息提示框思路并不复杂:

  1. 创建消息框,添加到body中
  2. 写消息框样式,包括图标,消息文本,关闭按钮
  3. 打开事件,关闭事件,持续时间(定时器),是否显示关闭按钮

    最终效果图
    js-message-box

创建Message类

es6代码,若需要兼容请用babel转一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class Message {
constructor() {
// 创建消息框元素并插入到body中
const containerId = 'message-container';
this.containerEl = document.getElementById(containerId);
if (!this.containerEl) {
this.containerEl = document.createElement('div');
this.containerEl.id = containerId;
document.body.appendChild(this.containerEl);
}
}
// type 消息类型 text 文本 duration 消息显示时间 closeable 是否显示关闭图标
show({ type = 'info', text = '', duration = 2000, closeable = false }) {
// 在消息框父元素中创建当前消息元素
let messageEl = document.createElement('div');
messageEl.className = type + ' message move-in';
messageEl.innerHTML = `<span class="iconfont icon-${type}"></span>`;

// 根据传参进行判断,有文本创建文本元素,需要关闭按钮则添加关闭元素
if (text) { // 若有文本消息则添加进消息元素内
let textEl = document.createElement('div');
textEl.className = 'text';
textEl.innerText = text
messageEl.appendChild(textEl);
}
if (closeable) { // 若需要关闭图标则创建关闭元素
let closeEl = document.createElement('div');
closeEl.className = 'close iconfont icon-close';
messageEl.appendChild(closeEl);
closeEl.addEventListener('click', () => {
this.close(messageEl) // 关闭当前消息元素
});
}

// 以上消息元素创建好后添加到父级消息框中
this.containerEl.appendChild(messageEl);

// 显示持续时间 默认显示2s,duration为0时,消息框不消失
if (duration > 0) {
setTimeout(() => {
this.close(messageEl); // 关闭当前消息元素
}, duration);
}
return messageEl
}

// 关闭事件处理,主要是对样式的处理
close(messageEl) {
messageEl.className = messageEl.className.replace('move-in', '');
// 增加一个move-out类
messageEl.className += 'move-out';

// move-out动画结束后把元素的高度和边距都设置为0
// 由于我们在css中设置了transition属性,所以会有一个过渡动画
messageEl.addEventListener('animationend', () => {
messageEl.setAttribute('style', 'height: 0; margin: 0');
});

// 这个地方是监听transition的过渡动画结束事件,在动画结束后把消息从dom树中移除。
messageEl.addEventListener('transitionend', () => {
// Element对象内部有一个remove方法,调用之后可以将该元素从dom树种移除!
messageEl.remove();
});
}
}
css样式

消息弹窗样式仿照element-ui的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
@font-face {font-family: "iconfont";
src: url('//at.alicdn.com/t/font_1452792_q7efevxgs5l.eot?t=1570779373612'); /* IE9 */
src: url('//at.alicdn.com/t/font_1452792_q7efevxgs5l.eot?t=1570779373612#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAU0AAsAAAAACqQAAATlAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDXgqHeIZkATYCJAMcCxAABCAFhG0HXBs4CRGVnOXJviiwm5Ft1dwCtrVTU6p3CE7FmFnvR28wn+ZDbb69YQb55LsIoSYGrUPN/dquR3b9xpodLajAZgrjCSVJkcH2HDCu932Xmj0AEUBZMHTipIM7vu+7rXuysh4vw0WoALaA9X+OpV60HZ7lv7YTPJSMtgo63BsPaEARzY0DLJC92XAgPB3gxp7a8GzsvBoIABmxyAZpbu1WIIGBtQRNs2dMmwCpZAPrIRNIRqHlSAayGzwkbhv3HsCu+OvJzygkEsCBp+A9+6e2TEa9FW29oppHMzp0YN/2PACc4wAKIBsAA8jmVp8GmuayQSHP1mdQAPhCAgdhW5+bZXVY/dYU65XHQ7mblxL4Sg5g4Lb7jyeAB4gAQ+cN7PC8AFjRvgAYYGUJgAOsDgFQwOoXAAGsKbL19K9gA2+ixSN8ASQDpBggF8GSXAadz71o8gUBJXi3V2QA8Y72CSMS70WvEe3N2AS/2X4rA5YHrJx17JX5QntuvBz+8Oa5e1G33KX7D4ZdepfywOlwRBx4YAYfdkx1OIlgugm6i2A4zCtW+X9DcTrtbvcwl2vMAe2yEaoq+42retgw9aB+zQyxDztkXtGCFQ1FHTF5f/6gHjZ0qPdMIQMHtGBCVh0ww/SDxn7lgKkbgdjWHio5VS05/cAR85h+1DisalfMa/pV4zKJGHbkBz8xn+lPjcf2Iy/MV/pL47ldI+yJX1k07Jr+qZGuqFeNj7UMu3JZ+8TMGma/Yn6mZx712xwtExuRqa25IGeTr6Mcw9eWfjziZs3p6GcpPstql1Uvr12e9JYfOWPV/javgaD+1B8qm95+H9yXPTxKGZq1PPXwH4NeBmN0/fGNm47XPT1Wt2lT3fGnnnvTxmPmWY7XbdxYf7zizW3E0/oX7N9/2QsRh5JAlXeIQ0ciEyOPHObhEsmaiDrSP/+IQym68va/FYnNvsq164GlWU3SM2Z8953imu0t/gMAKL59lJd5LokvWrdZDgkNudkrbvU77HfEb9tTIr8PlsoLnbY/Iv4Ix74L8yuMKYwtiinKPBs4NUkFx9TEk/RIGuIoY/pK4X1O5dFKya/ArxC5G0FyUSn2PzUxdmnV1OqpVUsXXIi/Un+lAefL/oj7uuV9ywct32DrOofjRc+Rnq8crPkqQb3oU1sD8TTrPvvjD3ZfxKEkUOWRbStVu4nA3msBAJ45A/cL4HmN1qwHPG+8onWAx7zOV7QFAOgq7h/wOF2jWV/r78FO5Zk8zq/aYMk2APBF52Pp9mTr5SUcqOVfYrlyis2VbBc3HezLlAzRCqMMB5BlAfjqhgL9bc8Qotbhf2IIyYEjigFKkoxk2Gzg2RSDQFIHsiyn422CiDqyD5Dpi4Dw9w0cX6+A8veDZNhf4IX6B4F/FGRq8zPapDajtxMYRUDXF8WWC+c5tZc0XxDeMiNFZUz9hPg4Sevc/GrxhAKyjX38PdyoOnLCOR3pesgyplI4gdVFpFpul3lT2x5oYTmv9DQRYCgIkKsXErNYwYXLq17t8y8gdJMxpKfvTPgTCC9ePVlbWCmQJ12h6nssnd5daEONjEOc08hy5Gh4IJMcI2X7Zgmw1EK0Rqa0tTTmOa1usX9D/jivAJDxOcSOztbV3dOL/df+/k2IsLT9zVp4387YBHERNm3GHu2HkaJkrVQAAAAA') format('woff2'),
url('//at.alicdn.com/t/font_1452792_q7efevxgs5l.woff?t=1570779373612') format('woff'),
url('//at.alicdn.com/t/font_1452792_q7efevxgs5l.ttf?t=1570779373612') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('//at.alicdn.com/t/font_1452792_q7efevxgs5l.svg?t=1570779373612#iconfont') format('svg'); /* iOS 4.1- */
}

.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

.icon-info:before {
content: "\e650";
}

.icon-error:before {
content: "\e62b";
}

.icon-success:before {
content: "\e649";
}

.icon-loading:before {
content: "\e61c";
}

.icon-close:before {
content: "\e6bf";
}

.icon-warning:before {
content: "\e665";
}

#message-container {
position: fixed;
left: 0;
top: 0;
right: 0;
display: flex;
flex-direction: column;
align-items: center;
}
#message-container .message {
background-color: #edf2fc;
margin: 10px 0;
padding: 5px 5px 5px 10px;
height: 40px;
box-shadow: 0 0 10px 0 #eee;
font-size: 14px;
border-radius: 3px;
display: flex;
align-items: center;
/* 增加一个过渡属性,当message元素的高度和margin变化时候将会有一个过渡动画 */
transition: height 0.2s ease-in-out, margin 0.2s ease-in-out;
}
#message-container .message.error {
color: #f56c6c;
background-color: #fef0f0;
border-color: #fde2e2;
}
#message-container .message.info {
color: #909399;
}
#message-container .message.success {
color: #67C23A;
background-color: #f0f9eb;
border-color: #e1f3d8;
}
#message-container .message.warning {
color: #E6A23C;
background-color: #fdf6ec;
border-color: #faecd8;
}
#message-container .message.loading {
background-color: transparent;
}
#message-container .message .text {
padding: 0 20px 0 5px;
}
#message-container .message .close {
cursor: pointer;
color: #999;
}
#message-container .message .icon-loading {
font-size: 28px;
animation: loading 1s linear infinite;
}
@keyframes loading {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}

@keyframes message-move-in {
0% {
opacity: 0;
transform: translateY(-100%);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
#message-container .message.move-in {
animation: message-move-in 0.3s ease-in-out;
}
@keyframes message-move-out {
0% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(-100%);
}
}
#message-container .message.move-out {
animation: message-move-out 0.3s ease-in-out;
animation-fill-mode: forwards;
}
使用
1
2
3
4
5
6
7
8
var Msg = new Message();
// type: error/success/info/warning/loading
// duration 显示时间 0 为不消失
// closeable 是否显示关闭按钮
Msg.show({ type: 'error', text: '这里是显示的消息', duration: 0, closeable: false });
// 自主关闭弹窗
var element = Msg.show({ type: 'loading', text: '正在加载中', duration: 0, closeable: false });
Msg.close(element)
babel && autoprefixer

autoprefixer online
babel online

------ 本文结束------
坚持原创技术分享,您的支持将鼓励我继续创作!