Skip to content

Commit e328b61

Browse files
committed
ADDED: add notification demo
1 parent 6835855 commit e328b61

File tree

2 files changed

+390
-0
lines changed

2 files changed

+390
-0
lines changed

notification(over)/demo.html

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
7+
<title>Document</title>
8+
<style>
9+
@keyframes enter {
10+
from{
11+
opacity: 0;
12+
transform: scale(1.1);
13+
}
14+
to {
15+
opacity: 1;
16+
transform: scale(1);
17+
}
18+
}
19+
20+
@keyframes out {
21+
from{
22+
opacity: 1;
23+
transform: scale(1);
24+
}
25+
to {
26+
opacity: 0;
27+
transform: scale(0);
28+
}
29+
}
30+
31+
.classEnter {
32+
/* opacity: 0; */
33+
animation: enter 1000ms ease-in;
34+
}
35+
.classOut {
36+
animation: out 3000ms ease-in;
37+
}
38+
.AgamennonNotiContainer {
39+
position: fixed;
40+
right: 0;
41+
top: 10px;
42+
width: 100%;
43+
display: flex;
44+
flex-direction: column;
45+
align-items: flex-end;
46+
pointer-events: none;
47+
}
48+
.AgamennonNotiContainer .AgamennonNotiItem--Wrapper {
49+
width: 20%;
50+
background-color: rgb(233, 241, 255);
51+
color: rgb(66, 132, 245);
52+
opacity: 1;
53+
z-index: 1020;
54+
padding: 15px 40px 15px 50px;
55+
border-color: rgb(180, 208, 255);
56+
border-radius: 5px;
57+
margin-bottom: 10px;
58+
margin-right: 10px;
59+
pointer-events: auto;
60+
position:relative;
61+
}
62+
.AgamennonNotiContainer .AgamennonNotiItem--title {
63+
display: block;
64+
margin-bottom: 5px;
65+
font-size: 18px;
66+
}
67+
.AgamennonNotiContainer .AgamennonNotiItem--message {
68+
display: block;
69+
margin-bottom: 5px;
70+
font-size: 12px;
71+
}
72+
.AgamennonNotiContainer .AgamennonNotiItem--close{
73+
position: absolute;
74+
top: 50%;
75+
transform: translateY(-50%);
76+
font-size: 14px;
77+
cursor: pointer;
78+
right: 16px;
79+
}
80+
</style>
81+
82+
</head>
83+
<body>
84+
<button id="addMessage">add message</button>
85+
<div class="AgamennonNotiContainer"></div>
86+
<script src="./index.js" defer></script>
87+
<script>
88+
window.onload = function () {
89+
document.querySelector('#addMessage').addEventListener('click', () => {
90+
show({
91+
message: 'tets',
92+
title: 'xx',
93+
duration: 3000,
94+
type: "warning"
95+
})
96+
}, false)
97+
}
98+
</script>
99+
</body>
100+
</html>

notification(over)/index.js

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
(function(root, factory) {
2+
if (typeof define === 'function' && define.amd) {
3+
define(function() {
4+
return factory(root);
5+
});
6+
} else if (typeof exports === 'object') {
7+
module.exports = factory;
8+
} else {
9+
root.show = factory(root);
10+
}
11+
})(typeof self !== 'undefined' ? self : this, function(root) {
12+
'use strict';
13+
if (root.$message) {
14+
root.pre$message = root.$message;
15+
}
16+
// 声明局部变量
17+
18+
const _window = root;
19+
const _document = document;
20+
const defaultSlector = 'AgamennonNotiContainer';
21+
let listenContainer = false;
22+
let notificationId = 0;
23+
// 申请一块容器
24+
const notificationContainer = {};
25+
const noop = Function.prototype;
26+
/**
27+
* 可暂停的setTimeout任务
28+
* @param {Function} Execute 可执行函数
29+
* @param {Number} duration 延迟毫秒数
30+
*/
31+
function Timer(execute, duration) {
32+
this.duration = duration;
33+
this.execute = execute;
34+
this.start = Date.now();
35+
this.status = 0; // no start
36+
}
37+
Timer.prototype = {
38+
constructor: Timer,
39+
startGo: function() {
40+
this.timeId = setTimeout(this.execute, this.duration);
41+
this.start = Date.now();
42+
this.status = 1; // starting
43+
},
44+
pause: function() {
45+
let now = Date.now();
46+
if (this.status === 2) {
47+
// stop
48+
return this;
49+
}
50+
if (this.start + this.duration < now) {
51+
return this;
52+
}
53+
this.timeId && clearTimeout(this.timeId);
54+
this.duration = this.duration - (now - this.start);
55+
this.status = 2;
56+
return this;
57+
},
58+
resume: function() {
59+
if (this.status !== 2) {
60+
return this;
61+
}
62+
this.timeId = setTimeout(this.execute, this.duration);
63+
this.start = Date.now();
64+
this.status = 1;
65+
return this;
66+
},
67+
stop: function() {
68+
// debugger
69+
this.status = 1;
70+
clearTimeout(this.timeId);
71+
this.duration = null;
72+
this.execute = null;
73+
this.start = null;
74+
}
75+
};
76+
/**
77+
* 预设的配置样式
78+
*/
79+
const colorMaps = {
80+
success: {
81+
bgcolor: 'rgb(212, 237, 217)',
82+
color: 'rgb(20, 86, 35)',
83+
bdcolor: 'rgb(194, 230, 202)'
84+
},
85+
info: {
86+
bgcolor: 'rgb(208, 236, 240)',
87+
color: 'rgb(11, 84, 95)',
88+
bdcolor: 'rgb(190, 228, 235)'
89+
},
90+
danger: {
91+
bgcolor: 'rgb(248, 214, 217)',
92+
color: 'rgb(114, 27, 35)',
93+
bdcolor: 'rgb(245, 198, 202)'
94+
},
95+
warning: {
96+
bgcolor: 'rgb(255, 242, 205)',
97+
color: 'rgb(132, 100, 3)',
98+
bdcolor: 'rgb(255, 237, 185)'
99+
},
100+
secondary: {
101+
bgcolor: 'rgb(225, 227, 229)',
102+
color: 'rgb(56, 60, 65)',
103+
bdcolor: 'rgb(225, 227, 229)'
104+
}
105+
};
106+
/**
107+
* 将Itemwrapper写入适配样式
108+
*/
109+
const handleAlertTypeColorChoose = (ele) => (type) => (maps) => {
110+
if (!(ele instanceof HTMLElement)) {
111+
return;
112+
}
113+
// debugger
114+
const TypeColor = maps[type];
115+
Object.keys(TypeColor).forEach((item, index, source) => {
116+
if (item === 'bgcolor') {
117+
ele.style.backgroundColor = TypeColor[item];
118+
}
119+
if (item === 'color') {
120+
ele.style.color = TypeColor[item];
121+
}
122+
if (item === 'bdcolor') {
123+
ele.style.borderColor = TypeColor[item];
124+
}
125+
});
126+
};
127+
/**
128+
* 创建一个notification 容器
129+
*/
130+
const createNotificationContainer = function() {
131+
let Container = _document.querySelector('.' + defaultSlector);
132+
133+
if (Container === null) {
134+
Container = _document.createElement('div');
135+
Container.className = defaultSlector;
136+
_document.body.appendChild(Container);
137+
}
138+
139+
return Container;
140+
};
141+
/**
142+
* @param {Number} id 存储容器中的id值
143+
* @param {Number} duration 延迟毫秒数
144+
* @param {String} outClass 离开的添加类名
145+
* @param {Function} onClose 容器卸载执行的回调函数
146+
*/
147+
function handleAutoClose(id, duration, outClass, onClose) {
148+
if (notificationContainer[id] == null) {
149+
return;
150+
}
151+
const { instance } = notificationContainer[id];
152+
const Container = createNotificationContainer();
153+
const exca = () => {
154+
// debugger
155+
instance.className += ' classOut';
156+
instance.addEventListener('animationend', function() {
157+
Container.removeChild(instance);
158+
onClose && onClose(notificationContainer);
159+
});
160+
};
161+
162+
const timerRecord = new Timer(exca, duration);
163+
timerRecord.startGo();
164+
notificationContainer[id].timer = timerRecord;
165+
/**
166+
* 做hover 的时候暂停自动卸载
167+
*/
168+
if (listenContainer === false) {
169+
Container.addEventListener('click', function(e) {
170+
const target = e.target;
171+
if (/AgamennonNotiItem--close/.test(target.className)) {
172+
e.stopPropagation();
173+
e.stopImmediatePropagation();
174+
const parentNode = target.parentNode;
175+
const instanceid = parentNode.getAttribute('instanceid');
176+
notificationContainer[instanceid].timer.stop();
177+
const instance = notificationContainer[instanceid].instance;
178+
instance.className += ' classOut';
179+
instance.addEventListener('animationend', function() {
180+
Container.removeChild(instance);
181+
onClose && onClose(notificationContainer);
182+
});
183+
}
184+
});
185+
listenContainer = true;
186+
}
187+
}
188+
/**
189+
* 默认设置
190+
*/
191+
const defaultOptions = {
192+
autoClose: false,
193+
onClose: noop,
194+
duration: 2000,
195+
type: 'normal',
196+
message: '',
197+
content: '',
198+
outClassName: 'classOut',
199+
enterClassName: 'classEnter',
200+
colorMaps: colorMaps
201+
};
202+
/**
203+
* @param {String} string - 代过滤字符串
204+
* @return {String}
205+
*/
206+
function xssEscape(string) {
207+
return [
208+
['&', '&amp;'],
209+
[' ', '&nbsp;'],
210+
['<', '&lt;'],
211+
['>', '&gt;'],
212+
['\r\n', '<br/>'],
213+
['\n', '<br/>'],
214+
['"', '&quot;']
215+
].reduce(function(string, [pattern, replacement]) {
216+
return string.replace(new RegExp(pattern, 'g'), replacement);
217+
}, string);
218+
}
219+
/**
220+
* 直接用Template 插入Item内容
221+
* @param {String} title - Item title
222+
* @param {String} message - Item message
223+
* @param {Boolean} canClose - canClose choose show or not show close btn
224+
*/
225+
const Template = (title, message, canClose) => {
226+
return `
227+
<span class="AgamennonNotiItem--title">${xssEscape(title)}</span>
228+
<span class="AgamennonNotiItem--message">${xssEscape(message)}</span>
229+
<span class="AgamennonNotiItem--close">x</span>
230+
`;
231+
};
232+
/**
233+
* @param {String} type - ItemWrapper Html type
234+
* @param {String} className - ItemWrapper Html className
235+
* @return {HTMLElement}
236+
*/
237+
function GeneratorItem(type = 'div', className) {
238+
const Item = document.createElement(type);
239+
Item.className = className;
240+
return Item;
241+
}
242+
/**
243+
* @param {Object} options
244+
*/
245+
function show(options) {
246+
// 初始化options
247+
options = Object.assign(defaultOptions, options);
248+
249+
const Id = notificationId++;
250+
251+
// 获取容器
252+
const Container = createNotificationContainer();
253+
// 设定item
254+
const Item = GeneratorItem('div', 'AgamennonNotiItem--Wrapper classEnter');
255+
Item.setAttribute('instanceid', Id);
256+
Item.innerHTML = Template(options.title, options.message);
257+
258+
handleAlertTypeColorChoose(Item)(options.type)(options.colorMaps);
259+
Container.appendChild(Item);
260+
Item.addEventListener(
261+
'mouseover',
262+
function(e) {
263+
const target = e.target;
264+
const instanceid = target.getAttribute('instanceid');
265+
if (instanceid != null) {
266+
e.stopPropagation();
267+
notificationContainer[instanceid].timer.pause();
268+
}
269+
},
270+
false
271+
);
272+
Item.addEventListener(
273+
'mouseleave',
274+
function(e) {
275+
const target = e.target;
276+
const instanceid = target.getAttribute('instanceid');
277+
if (instanceid != null) {
278+
e.stopPropagation();
279+
notificationContainer[instanceid].timer.resume();
280+
}
281+
},
282+
false
283+
);
284+
notificationContainer[Id] = {
285+
instance: Item
286+
};
287+
handleAutoClose(Id, options.duration, options.outClassName, options.onClose);
288+
}
289+
return show;
290+
});

0 commit comments

Comments
 (0)