|
| 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 | + ['&', '&'], |
| 209 | + [' ', ' '], |
| 210 | + ['<', '<'], |
| 211 | + ['>', '>'], |
| 212 | + ['\r\n', '<br/>'], |
| 213 | + ['\n', '<br/>'], |
| 214 | + ['"', '"'] |
| 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