Qmsg

消息提示

当前为 2022-11-29 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/455576/1122349/Qmsg.js

  1. /**
  2. * 一款优雅的原生JS页面消息提示插件,兼容性良好,无任何依赖
  3. *
  4. * @author 或许吧(jesseqin)
  5. * @origin https://www.jq22.com/jquery-info23550
  6. * @modified Myles Yang
  7. * @gitee
  8. * @github
  9. */
  10. ;(function (root, Msg) {
  11. if (typeof exports === 'object' && typeof module !== 'undefined') {
  12. module.exports = Msg
  13. } else if (typeof define === 'function' && define.amd) {
  14. define([], function () {
  15. return Msg(root);
  16. });
  17. } else {
  18. root.Qmsg = Msg(root);
  19. }
  20. })(this, function (global) {
  21. 'use strict';
  22.  
  23. // assign 兼容处理
  24. if (typeof Object.assign != 'function') {
  25. Object.assign = function (target) {
  26. if (target == null) {
  27. throw new TypeError('Cannot convert undefined or null to object');
  28. }
  29.  
  30. target = Object(target);
  31. for (var index = 1; index < arguments.length; index++) {
  32. var source = arguments[index];
  33. if (source != null) {
  34. for (var key in source) {
  35. if (Object.prototype.hasOwnProperty.call(source, key)) {
  36. target[key] = source[key];
  37. }
  38. }
  39. }
  40. }
  41. return target;
  42. }
  43. }
  44.  
  45. // 'classList' 兼容处理,add,remove不支持传入多个cls参数
  46. if (!("classList" in document.documentElement)) {
  47. Object.defineProperty(HTMLElement.prototype, 'classList', {
  48. get: function () {
  49. var self = this;
  50.  
  51. function update(fn) {
  52. return function (value) {
  53. var classes = self.className.split(/\s+/g),
  54. index = classes.indexOf(value);
  55. fn(classes, index, value);
  56. self.className = classes.join(" ");
  57. }
  58. }
  59.  
  60. return {
  61. add: update(function (classes, index, value) {
  62. if (!~index) classes.push(value);
  63. }),
  64.  
  65. remove: update(function (classes, index) {
  66. if (~index) classes.splice(index, 1);
  67. }),
  68.  
  69. toggle: update(function (classes, index, value) {
  70. if (~index)
  71. classes.splice(index, 1);
  72. else
  73. classes.push(value);
  74. }),
  75.  
  76. contains: function (value) {
  77. return !!~self.className.split(/\s+/g).indexOf(value);
  78. },
  79.  
  80. item: function (i) {
  81. return self.className.split(/\s+/g)[i] || null;
  82. }
  83. };
  84. }
  85. });
  86. }
  87.  
  88. /**
  89. * 声明插件名称
  90. */
  91. var PLUGIN_NAME = "qmsg";
  92.  
  93. /**
  94. * 命名空间 用于css和事件
  95. */
  96. var NAMESPACE = global && global.QMSG_GLOBALS && global.QMSG_GLOBALS.NAMESPACE || PLUGIN_NAME;
  97.  
  98. /**
  99. * 状态 & 动画
  100. * 显示中,显示完成,关闭中
  101. */
  102. var STATES = {
  103. opening: 'MessageMoveIn',
  104. done: '',
  105. closing: 'MessageMoveOut'
  106. }
  107.  
  108. /**
  109. * 全局默认配置
  110. * 可在引入js之前通过QMSG_GLOBALS.DEFAULTS进行配置
  111. * position {String} 位置,仅支持'center','right','left',默认'center'
  112. * type {String} 类型,支持'info','warning','success','error','loading'
  113. * showClose {Boolean} 是否显示关闭图标,默认为false不显示
  114. * timeout {Number} 多久后自动关闭,单位ms,默认2500
  115. * autoClose {Boolean} 是否自动关闭,默认true,注意在type为loading的时候自动关闭为false
  116. * content {String} 提示的内容
  117. * onClose {Function} 关闭的回调函数
  118. */
  119. var DEFAULTS = Object.assign({
  120. position: 'center',
  121. type: "info",
  122. showClose: false,
  123. timeout: 2500,
  124. animation: true,
  125. autoClose: true,
  126. content: "",
  127. onClose: null,
  128. maxNums: 5,
  129. html: false
  130. }, global && global.QMSG_GLOBALS && global.QMSG_GLOBALS.DEFAULTS);
  131.  
  132. /**
  133. * 设置icon html代码
  134. */
  135. var ICONS = {
  136. info: '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M512 64q190.016 4.992 316.512 131.488T960 512q-4.992 190.016-131.488 316.512T512 960q-190.016-4.992-316.512-131.488T64 512q4.992-190.016 131.488-316.512T512 64zm67.008 275.008q26.016 0 43.008-15.488t16.992-41.504-16.992-41.504-42.496-15.488-42.496 15.488-16.992 41.504 16.992 41.504 42.016 15.488zm12 360q0-6.016.992-16T592 664l-52.992 60.992q-8 8.992-16.512 14.016T508 742.016q-8.992-4-8-14.016l88-276.992q4.992-28-8.992-48t-44.992-24q-35.008.992-76.512 29.504t-72.512 72.512v15.008q-.992 10.016 0 19.008l52.992-60.992q8-8.992 16.512-14.016T468 437.024q10.016 4.992 7.008 16l-87.008 276q-7.008 24.992 7.008 44.512T444 800.032q50.016-.992 84-28.992t63.008-72z" fill="#909399"/></svg>',
  137. warning: '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M512 64C264.64 64 64 264.64 64 512c0 247.424 200.64 448 448 448 247.488 0 448-200.576 448-448 0-247.36-200.512-448-448-448zm0 704c-26.432 0-48-21.504-48-48s21.568-48 48-48c26.624 0 48 21.504 48 48s-21.376 48-48 48zm48-240c0 26.56-21.376 48-48 48-26.432 0-48-21.44-48-48V304c0-26.56 21.568-48 48-48 26.624 0 48 21.44 48 48v224z" fill="#E6A23C"/></svg>',
  138. error: '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M512 64C264.58 64 64 264.58 64 512s200.58 448 448 448 448-200.57 448-448S759.42 64 512 64zm158.39 561.14a32 32 0 1 1-45.25 45.26L512 557.26 398.86 670.4a32 32 0 0 1-45.25-45.26L466.75 512 353.61 398.86a32 32 0 0 1 45.25-45.25L512 466.74l113.14-113.13a32 32 0 0 1 45.25 45.25L557.25 512z" fill="#F56C6C"/></svg>',
  139. success: '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M512 64q190.016 4.992 316.512 131.488T960 512q-4.992 190.016-131.488 316.512T512 960q-190.016-4.992-316.512-131.488T64 512q4.992-190.016 131.488-316.512T512 64zm-56 536l-99.008-99.008q-12-11.008-27.488-11.008t-27.008 11.488-11.488 26.496 11.008 27.008l127.008 127.008q11.008 11.008 27.008 11.008t27.008-11.008l263.008-263.008q15.008-15.008 9.504-36.512t-27.008-27.008-36.512 9.504z" fill="#67C23A"/></svg>',
  140. loading: '<svg class="animate-turn" width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" fill-opacity=".01" d="M0 0h48v48H0z"/><path d="M4 24c0 11.046 8.954 20 20 20s20-8.954 20-20S35.046 4 24 4" stroke="#409eff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M36 24c0-6.627-5.373-12-12-12s-12 5.373-12 12 5.373 12 12 12" stroke="#409eff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>',
  141. close: '<svg width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M14 14L34 34" stroke="#909399" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M14 34L34 14" stroke="#909399" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>',
  142. }
  143.  
  144. /**
  145. * 是否支持动画属性
  146. * @type {Boolean}
  147. */
  148. var CAN_ANIMATION = (function () {
  149. var style = document.createElement('div').style;
  150. return style.animationName !== undefined ||
  151. style.WebkitAnimationName !== undefined ||
  152. style.MozAnimationName !== undefined ||
  153. style.msAnimationName !== undefined ||
  154. style.OAnimationName !== undefined;
  155. })();
  156.  
  157. /**
  158. * 生成带插件名的名称
  159. * @param {...String}
  160. * @returns {String}
  161. */
  162. function namespacify() {
  163. var res = NAMESPACE;
  164. for (var i = 0; i < arguments.length; ++i) {
  165. res += '-' + arguments[i];
  166. }
  167. return res;
  168. }
  169.  
  170. /**
  171. * 每条消息的构造函数
  172. * @param {Objetc} opts 配置参数,参考DEFAULTS
  173. */
  174. function Msg(opts) {
  175. var oMsg = this;
  176. oMsg.settings = Object.assign({}, DEFAULTS, opts || {});
  177. oMsg.id = Qmsg.instanceCount;
  178. var timeout = oMsg.settings.timeout;
  179. timeout = timeout && parseInt(timeout >= 0) && parseInt(timeout) <= Math.NEGATIVE_INFINITY ? parseInt(timeout) : DEFAULTS.timeout;
  180. oMsg.timeout = timeout;
  181. oMsg.settings.timeout = timeout;
  182. oMsg.timer = null;
  183. var $elem = document.createElement("div");
  184. var $svg = ICONS[oMsg.settings.type || 'info'];
  185. var contentClassName = namespacify("content-" + oMsg.settings.type || 'info');
  186. contentClassName += oMsg.settings.showClose ? ' ' + namespacify('content-with-close') : ''
  187. var content = oMsg.settings.content || '';
  188. var $closeSvg = ICONS['close'];
  189. var $closeIcon = oMsg.settings.showClose ? '<i class="qmsg-icon qmsg-icon-close">' + $closeSvg + '</i>' : '';
  190. var $span = document.createElement("span");
  191. if (oMsg.settings.html) {
  192. $span.innerHTML = content;
  193. } else {
  194. $span.innerText = content;
  195. }
  196. $elem.innerHTML = '<div class="qmsg-content">\
  197. <div class="' + contentClassName + '">\
  198. <i class="qmsg-icon">' + $svg + '</i>' + $span.outerHTML + $closeIcon +
  199. '</div>\
  200. </div>';
  201.  
  202. $elem.classList.add(namespacify('item'));
  203. $elem.style.textAlign = oMsg.settings.position;
  204. var $wrapper = document.querySelector('.' + NAMESPACE);
  205. if (!$wrapper) {
  206. $wrapper = document.createElement("div");
  207. // $wrapper.classList.add(NAMESPACE, namespacify('wrapper'), namespacify('is-initialized'));
  208. $wrapper.classList.add(NAMESPACE);
  209. $wrapper.classList.add(namespacify('wrapper'));
  210. $wrapper.classList.add(namespacify('is-initialized'));
  211. document.body.appendChild($wrapper);
  212. }
  213. $wrapper.appendChild($elem);
  214. oMsg.$wrapper = $wrapper;
  215. oMsg.$elem = $elem;
  216. setState(oMsg, 'opening');
  217. if (oMsg.settings.showClose) { // 关闭按钮绑定点击事件
  218. $elem.querySelector(".qmsg-icon-close").addEventListener('click', function () {
  219. oMsg.close();
  220. }.bind($elem));
  221. }
  222. $elem.addEventListener("animationend", function (e) { // 监听动画完成
  223. var target = e.target, animationName = e.animationName;
  224. if (animationName === STATES['closing']) {
  225. clearInterval(this.timer);
  226. this.destroy();
  227. }
  228. target.style.animationName = '';
  229. }.bind(oMsg));
  230. if (oMsg.settings.autoClose) { // 自动关闭
  231. var intvMs = 10; // 定时器频率
  232. oMsg.timer = setInterval(function () {
  233. this.timeout -= intvMs;
  234. if (this.timeout <= 0) {
  235. clearInterval(this.timer)
  236. this.close();
  237. }
  238. }.bind(oMsg), intvMs);
  239. oMsg.$elem.addEventListener('mouseover', function () {
  240. clearInterval(this.timer)
  241. }.bind(oMsg));
  242. oMsg.$elem.addEventListener('mouseout', function () {
  243. if (this.state !== 'closing') { // 状态为关闭则不重启定时器
  244. this.timer = setInterval(function () {
  245. this.timeout -= intvMs;
  246. if (this.timeout <= 0) {
  247. clearInterval(this.timer);
  248. this.close();
  249. }
  250. }.bind(oMsg), intvMs);
  251. }
  252. }.bind(oMsg));
  253. }
  254. }
  255.  
  256. function setState(inst, state) {
  257. if (!state || !STATES[state]) return;
  258. inst.state = state;
  259. inst.$elem.style.animationName = STATES[state];
  260. }
  261.  
  262. /**
  263. * 直接销毁元素,不会触发关闭回调函数
  264. */
  265. Msg.prototype.destroy = function () {
  266. this.$elem.parentNode && this.$elem.parentNode.removeChild(this.$elem);
  267. clearInterval(this.timer);
  268. Qmsg.remove(this.id);
  269. }
  270. /**
  271. * 关闭,支持动画则会触发动画事件
  272. */
  273. Msg.prototype.close = function () {
  274. setState(this, 'closing');
  275. if (!CAN_ANIMATION) { // 不支持动画
  276. this.destroy();
  277. } else {
  278. Qmsg.remove(this.id);
  279. }
  280. var callback = this.settings.onClose;
  281. if (callback && callback instanceof Function) {
  282. callback.call(this);
  283. }
  284. }
  285.  
  286. /**
  287. * 设置消息数量统计
  288. * @private
  289. */
  290. function setMsgCount(oMsg) {
  291. var countClassName = namespacify('count');
  292. var $content = oMsg.$elem.querySelector('[class^="qmsg-content-"]'),
  293. $count = $content.querySelector('.' + countClassName);
  294. if (!$count) {
  295. $count = document.createElement("span");
  296. $count.classList.add(countClassName);
  297. $content.appendChild($count);
  298. }
  299. $count.innerHTML = oMsg.count;
  300. $count.style.animationName = "";
  301. $count.style.animationName = "MessageShake";
  302. oMsg.timeout = oMsg.settings.timeout || DEFAULTS.timeout;
  303. }
  304.  
  305. /**
  306. * 合并参数为配置信息,用于创建Msg实例
  307. * @param {String} txt 文本内容
  308. * @param {Object} config 配置
  309. * @private
  310. */
  311. function mergeArgs(txt, config) {
  312. var opts = Object.assign({}, DEFAULTS);
  313. if (arguments.length === 0) {
  314. return opts;
  315. }
  316. if (txt instanceof Object) {
  317. return Object.assign(opts, txt);
  318. } else {
  319. opts.content = txt.toString();
  320. }
  321. if (config instanceof Object) {
  322. return Object.assign(opts, config)
  323. }
  324. return opts;
  325. }
  326.  
  327. /**
  328. * 通过配置信息 来判断是否为同一条消息,并返回消息实例
  329. * @param {Object} params 配置项
  330. * @private
  331. */
  332. function judgeReMsg(params) {
  333. params = params || {};
  334. var opt = JSON.stringify(params)
  335. var oInx = -1;
  336. var oMsg;
  337. for (var i in this.oMsgs) {
  338. var oMsgItem = this.oMsgs[i];
  339. if (oMsgItem.config === opt) {
  340. oInx = i;
  341. oMsg = oMsgItem.inst;
  342. break;
  343. }
  344. }
  345. if (oInx < 0) {
  346. this.instanceCount++;
  347. var oItem = {};
  348. oItem.id = this.instanceCount;
  349. oItem.config = opt;
  350. oMsg = new Msg(params);
  351. oMsg.id = this.instanceCount;
  352. oMsg.count = '';
  353. oItem.inst = oMsg;
  354. this.oMsgs[this.instanceCount] = oItem;
  355. var len = this.oMsgs.length;
  356. var maxNums = this.maxNums;
  357. /**
  358. * 关闭多余的消息
  359. */
  360. if (len > maxNums) {
  361. var oIndex = 0;
  362. var oMsgs = this.oMsgs;
  363. for (oIndex; oIndex < len - maxNums; oIndex++) {
  364. oMsgs[oIndex] && oMsgs[oIndex].inst.settings.autoClose && oMsgs[oIndex].inst.close();
  365. }
  366. }
  367. } else {
  368. oMsg.count = !oMsg.count ? 2 : oMsg.count >= 99 ? oMsg.count : oMsg.count + 1;
  369. setMsgCount(oMsg);
  370. }
  371. oMsg.$elem.setAttribute("data-count", oMsg.count);
  372. return oMsg;
  373. }
  374.  
  375.  
  376. var Qmsg = {
  377. version: '0.0.1',
  378. instanceCount: 0,
  379. oMsgs: [],
  380. maxNums: DEFAULTS.maxNums || 5,
  381. config: function (cfg) {
  382. DEFAULTS = cfg && cfg instanceof Object ? Object.assign(DEFAULTS, cfg) : DEFAULTS;
  383. this.maxNums = DEFAULTS.maxNums && DEFAULTS.maxNums > 0 ? parseInt(DEFAULTS.maxNums) : 3;
  384. },
  385. info: function (txt, config) {
  386. var params = mergeArgs(txt, config);
  387. params.type = 'info';
  388. return judgeReMsg.call(this, params);
  389. },
  390. warning: function (txt, config) {
  391. var params = mergeArgs(txt, config);
  392. params.type = 'warning';
  393. return judgeReMsg.call(this, params);
  394. },
  395. success: function (txt, config) {
  396. var params = mergeArgs(txt, config);
  397. params.type = 'success';
  398. return judgeReMsg.call(this, params);
  399. },
  400. error: function (txt, config) {
  401. var params = mergeArgs(txt, config);
  402. params.type = 'error';
  403. return judgeReMsg.call(this, params);
  404. },
  405. loading: function (txt, config) {
  406. var params = mergeArgs(txt, config);
  407. params.type = 'loading';
  408. params.autoClose = false;
  409. return judgeReMsg.call(this, params);
  410. },
  411. remove: function (id) {
  412. this.oMsgs[id] && delete this.oMsgs[id];
  413. },
  414. closeAll: function () {
  415. for (var i in this.oMsgs) {
  416. this.oMsgs[i] && this.oMsgs[i].inst.close();
  417. }
  418. }
  419. }
  420.  
  421. return Qmsg;
  422. })

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址