Greasy Fork is available in English.

Message

一款优雅的原生JS页面消息提示插件,兼容性良好,无任何依赖。 An elegant native JS page message prompt plug-in, good compatibility, no dependency.

Tätä skriptiä ei tulisi asentaa suoraan. Se on kirjasto muita skriptejä varten sisällytettäväksi metadirektiivillä // @require https://update.greasyfork.org/scripts/462234/1497815/Message.js.

  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Qmsg = factory());
  5. })(this, (function () { 'use strict';
  6.  
  7. /**
  8. * 兼容处理
  9. */
  10. function CompatibleProcessing() {
  11. /* 处理Object.assign不存在的问题 */
  12. try {
  13. if (typeof Object.assign !== "function") {
  14. Object.assign = function (target) {
  15. target = Object(target);
  16. if (arguments.length > 1) {
  17. let sourceList = [...arguments].splice(1, arguments.length - 1);
  18. sourceList.forEach((sourceItem) => {
  19. for (var sourceKey in sourceItem) {
  20. if (Object.prototype.hasOwnProperty.call(sourceItem, sourceKey)) {
  21. target[sourceKey] = sourceItem[sourceKey];
  22. }
  23. }
  24. });
  25. }
  26. return target;
  27. };
  28. }
  29. }
  30. catch (error) {
  31. console.warn(error);
  32. }
  33. /* 'classList' 兼容处理,add,remove不支持传入多个cls参数 */
  34. try {
  35. if (!("classList" in document.documentElement)) {
  36. Object.defineProperty(HTMLElement.prototype, "classList", {
  37. get: function () {
  38. var self = this;
  39. function update(fn) {
  40. return function (value) {
  41. var classes = self.className.split(/\s+/g), index = classes.indexOf(value);
  42. fn(classes, index, value);
  43. self.className = classes.join(" ");
  44. };
  45. }
  46. return {
  47. add: update(function (classes, index, value) {
  48. if (!~index)
  49. classes.push(value);
  50. }),
  51. remove: update(function (classes, index) {
  52. if (~index)
  53. classes.splice(index, 1);
  54. }),
  55. toggle: update(function (classes, index, value) {
  56. if (~index)
  57. classes.splice(index, 1);
  58. else
  59. classes.push(value);
  60. }),
  61. contains: function (value) {
  62. return !!~self.className.split(/\s+/g).indexOf(value);
  63. },
  64. item: function (index) {
  65. return self.className.split(/\s+/g)[index] || null;
  66. },
  67. };
  68. },
  69. });
  70. }
  71. }
  72. catch (error) {
  73. console.warn(error);
  74. }
  75. }
  76.  
  77. const QmsgAnimation = {
  78. /** 状态 & 动画 */
  79. $state: {
  80. opening: "MessageMoveIn",
  81. done: "",
  82. closing: "MessageMoveOut",
  83. },
  84. $name: {
  85. startNameList: [
  86. "animationName",
  87. "WebkitAnimationName",
  88. "MozAnimationName",
  89. "msAnimationName",
  90. "OAnimationName",
  91. ],
  92. endNameList: [
  93. "animationend",
  94. "webkitAnimationEnd",
  95. "mozAnimationEnd",
  96. "MSAnimationEnd",
  97. "oanimationend",
  98. ],
  99. },
  100. /**
  101. * 获取元素上的animationName属性
  102. * @param element
  103. */
  104. getStyleAnimationNameValue(element) {
  105. for (let index = 0; index < this.$name.startNameList.length; index++) {
  106. let animationName = this.$name.startNameList[index];
  107. let animationNameValue = element.style[animationName];
  108. if (animationNameValue != null) {
  109. return animationNameValue;
  110. }
  111. }
  112. },
  113. /**
  114. * 设置元素上的animationName属性
  115. * @param element
  116. * @param animationNameValue
  117. */
  118. setStyleAnimationName(element, animationNameValue = "") {
  119. this.$name.startNameList.forEach((animationName) => {
  120. if (animationName in element.style) {
  121. element.style[animationName] = animationNameValue;
  122. }
  123. });
  124. },
  125. };
  126.  
  127. const QmsgConfig = {
  128. /** 声明插件名称 */
  129. PLUGIN_NAME: "qmsg",
  130. /** 命名空间,用于css和事件 */
  131. NAMESPACE: "qmsg",
  132. /** 实例配置的固定的默认值 */
  133. INS_DEFAULT: {},
  134. /** 固定的默认值 */
  135. DEFAULT: {
  136. animation: true,
  137. autoClose: true,
  138. content: "",
  139. html: false,
  140. isHTML: false,
  141. position: "top",
  142. showClose: false,
  143. maxNums: 5,
  144. onClose: null,
  145. showIcon: true,
  146. showMoreContent: false,
  147. showReverse: false,
  148. timeout: 2500,
  149. type: "info",
  150. zIndex: 50000,
  151. style: "",
  152. customClass: "",
  153. isLimitWidth: false,
  154. limitWidthNum: 200,
  155. limitWidthWrap: "no-wrap",
  156. consoleLogContent: false,
  157. },
  158. /**
  159. * 是否支持动画属性
  160. */
  161. CAN_ANIMATION: Boolean(QmsgAnimation.getStyleAnimationNameValue(document.createElement("div")) !=
  162. null),
  163. };
  164.  
  165. const QmsgHeaderCloseIcon = '<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>';
  166. const QmsgIcon = {
  167. 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>',
  168. 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>',
  169. 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>',
  170. 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>',
  171. 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>',
  172. };
  173.  
  174. const QmsgInstanceStorage = {
  175. QmsgList: [],
  176. /**
  177. * 移除实例
  178. * @param uuid
  179. */
  180. remove(uuid) {
  181. for (let index = 0; index < QmsgInstanceStorage.QmsgList.length; index++) {
  182. if (QmsgInstanceStorage.QmsgList[index].uuid === uuid) {
  183. QmsgInstanceStorage.QmsgList.splice(index, 1);
  184. return;
  185. }
  186. }
  187. },
  188. };
  189.  
  190. const QmsgCSS = {
  191. css: `@charset "utf-8";
  192. .qmsg.qmsg-wrapper{position:fixed;top:16px;left:0;z-index:50000;display:flex;box-sizing:border-box;margin:0;padding:0;width:100%;color:rgba(0,0,0,.55);list-style:none;font-variant:tabular-nums;font-size:13px;line-height:1;font-feature-settings:"tnum";pointer-events:none;flex-direction:column;}
  193. .qmsg.qmsg-data-position-center,.qmsg.qmsg-data-position-left,.qmsg.qmsg-data-position-right{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);}
  194. .qmsg.qmsg-data-position-bottom,.qmsg.qmsg-data-position-bottomleft,.qmsg.qmsg-data-position-bottomright{position:fixed;top:unset;bottom:0;bottom:8px;left:50%;transform:translate(-50%,0);}
  195. .qmsg.qmsg-data-position-bottomleft .qmsg-item,.qmsg.qmsg-data-position-left .qmsg-item,.qmsg.qmsg-data-position-topleft .qmsg-item{text-align:left;}
  196. .qmsg.qmsg-data-position-bottom .qmsg-item,.qmsg.qmsg-data-position-center .qmsg-item,.qmsg.qmsg-data-position-top .qmsg-item{text-align:center;}
  197. .qmsg.qmsg-data-position-bottomright .qmsg-item,.qmsg.qmsg-data-position-right .qmsg-item,.qmsg.qmsg-data-position-topright .qmsg-item{text-align:right;}
  198. .qmsg .qmsg-item{position:relative;padding:8px;text-align:center;-webkit-animation-duration:.3s;animation-duration:.3s;}
  199. .qmsg .qmsg-item .qmsg-count{position:absolute;top:-4px;left:-4px;display:inline-block;height:16px;min-width:16px;border-radius:2px;background-color:red;color:#fff;text-align:center;font-size:12px;line-height:16px;-webkit-animation-duration:.3s;animation-duration:.3s;}
  200. .qmsg .qmsg-item:first-child{margin-top:-8px;}
  201. .qmsg .qmsg-content{position:relative;display:inline-block;padding:10px 12px;max-width:80%;min-width:40px;border-radius:4px;background:#fff;box-shadow:0 4px 12px rgba(0,0,0,.15);text-align:center;pointer-events:all;}
  202. .qmsg .qmsg-content [class^=qmsg-content-]{display:flex;align-items:center;}
  203. .qmsg .qmsg-icon{position:relative;top:1px;display:inline-block;margin-right:8px;color:inherit;vertical-align:-.125em;text-align:center;text-transform:none;font-style:normal;font-size:16px;line-height:0;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}
  204. .qmsg .qmsg-icon svg{display:inline-block;}
  205. .qmsg .qmsg-content .qmsg-show-more-content{display:flex;align-items:center;white-space:unset;overflow:unset;text-overflow:unset;padding-right:unset}
  206. .qmsg .qmsg-content-info .qmsg-icon{color:#1890ff;}
  207. .qmsg .qmsg-icon-close{margin:0;margin-left:8px;padding:0;outline:0;border:none;background-color:transparent;color:rgba(0,0,0,.45);font-size:12px;cursor:pointer;transition:color .3s;}
  208. .qmsg .qmsg-icon-close:hover>svg path{stroke:#555;}
  209. .qmsg .qmsg-icon-close.qmsg-show-more-content{position:unset;overflow:unset;padding-left:6px;margin-right:0}
  210. .qmsg .animate-turn{animation:MessageTurn 1s linear infinite;-webkit-animation:MessageTurn 1s linear infinite;}
  211. @keyframes MessageTurn{
  212. 0%{-webkit-transform:rotate(0);}
  213. 25%{-webkit-transform:rotate(90deg);}
  214. 50%{-webkit-transform:rotate(180deg);}
  215. 75%{-webkit-transform:rotate(270deg);}
  216. 100%{-webkit-transform:rotate(360deg);}
  217. }
  218. @-webkit-keyframes MessageTurn{
  219. 0%{-webkit-transform:rotate(0);}
  220. 25%{-webkit-transform:rotate(90deg);}
  221. 50%{-webkit-transform:rotate(180deg);}
  222. 75%{-webkit-transform:rotate(270deg);}
  223. 100%{-webkit-transform:rotate(360deg);}
  224. }
  225. @-webkit-keyframes MessageMoveOut{
  226. 0%{max-height:150px;opacity:1;}
  227. to{max-height:0;opacity:0;}
  228. }
  229. @keyframes MessageMoveOut{
  230. 0%{max-height:150px;opacity:1;}
  231. to{max-height:0;opacity:0;}
  232. }
  233. @-webkit-keyframes MessageMoveIn{
  234. 0%{opacity:0;transform:translateY(-100%);transform-origin:0 0;}
  235. to{opacity:1;transform:translateY(0);transform-origin:0 0;}
  236. }
  237. @keyframes MessageMoveIn{
  238. 0%{opacity:0;transform:translateY(-100%);transform-origin:0 0;}
  239. to{opacity:1;transform:translateY(0);transform-origin:0 0;}
  240. }
  241. @-webkit-keyframes MessageShake{
  242. 0%,100%{opacity:1;transform:translateX(0);}
  243. 25%,75%{opacity:.75;transform:translateX(-4px);}
  244. 50%{opacity:.25;transform:translateX(4px);}
  245. }
  246. @keyframes MessageShake{
  247. 0%,100%{opacity:1;transform:translateX(0);}
  248. 25%,75%{opacity:.75;transform:translateX(-4px);}
  249. 50%{opacity:.25;transform:translateX(4px);}
  250. }`,
  251. /**
  252. * 获取CSS元素
  253. */
  254. getStyleElement() {
  255. let cssResourceNode = document.createElement("style");
  256. cssResourceNode.setAttribute("type", "text/css");
  257. cssResourceNode.setAttribute("data-type", QmsgConfig.PLUGIN_NAME);
  258. cssResourceNode.innerHTML = this.css;
  259. return cssResourceNode;
  260. },
  261. };
  262.  
  263. /**
  264. * 每条消息的构造函数
  265. */
  266. class QmsgMsg {
  267. /**
  268. * setTimeout的id
  269. */
  270. timeId;
  271. /**
  272. * 启动时间
  273. */
  274. startTime;
  275. /**
  276. * 关闭时间
  277. */
  278. endTime;
  279. /**
  280. * Qmsg的配置
  281. */
  282. setting;
  283. /**
  284. * uuid
  285. */
  286. uuid;
  287. /**
  288. * 当前动画状态
  289. */
  290. state;
  291. /**
  292. * 当前相同消息的数量
  293. */
  294. repeatNum;
  295. /**
  296. * 主元素
  297. */
  298. $Qmsg;
  299. constructor(option, uuid) {
  300. this.timeId = void 0;
  301. this.startTime = Date.now();
  302. this.endTime = null;
  303. // this.#setting = Object.assign({}, QmsgStore.DEFAULT, this.option);
  304. this.setting = QmsgUtils.toDynamicObject(QmsgConfig.DEFAULT, option, QmsgConfig.INS_DEFAULT);
  305. this.uuid = uuid;
  306. this.state = "opening";
  307. this.$Qmsg = document.createElement("div");
  308. this.repeatNum = 1;
  309. this.detectionType();
  310. this.init();
  311. if (this.setting.consoleLogContent) {
  312. // 控制台输出content
  313. console.log(this.setting.content);
  314. }
  315. }
  316. /**
  317. * 获取当前配置
  318. * @returns
  319. */
  320. getSetting() {
  321. return this.setting;
  322. }
  323. /**
  324. * 获取当前相同的数量
  325. * @returns
  326. */
  327. getRepeatNum() {
  328. return this.repeatNum;
  329. }
  330. /**
  331. * 设置repeatNum值
  332. * @param num 重复的数量
  333. */
  334. setRepeatNum(num) {
  335. this.repeatNum = num;
  336. }
  337. /**
  338. * 设置repeatNum自增
  339. */
  340. setRepeatNumIncreasing() {
  341. this.repeatNum++;
  342. }
  343. /**
  344. * 初始化元素
  345. */
  346. init() {
  347. let QmsgContext = this;
  348. if (this.setting.customClass &&
  349. typeof this.setting.customClass === "string") {
  350. /* 设置自定义类名 */
  351. this.$Qmsg.classList.add(this.setting.customClass);
  352. }
  353. // 设置svg图标
  354. let $svg = QmsgIcon[this.setting.type || "info"];
  355. let contentClassName = QmsgUtils.getNameSpacify("content-" + this.setting.type || "info");
  356. if (this.setting.showClose) {
  357. // 显示 关闭图标
  358. contentClassName += " " + QmsgUtils.getNameSpacify("content-with-close");
  359. }
  360. // 内容兼容处理
  361. let content = this.setting.content || "";
  362. // 关闭图标 自定义额外className
  363. let extraCloseIconClassName = "";
  364. // 关闭图标svg
  365. let $closeSvg = QmsgHeaderCloseIcon;
  366. if (this.setting.showMoreContent) {
  367. // 显示更多内容
  368. contentClassName += "qmsg-show-more-content";
  369. extraCloseIconClassName += "qmsg-show-more-content";
  370. }
  371. let $closeIcon = "";
  372. if (this.setting.showClose) {
  373. /* 显示右上角的关闭图标按钮 */
  374. $closeIcon = `<i class="qmsg-icon qmsg-icon-close ${extraCloseIconClassName}">${$closeSvg}</i>`;
  375. }
  376. /* 内容 */
  377. let $content = document.createElement("span");
  378. let $positionClassName = QmsgUtils.getNameSpacify("data-position", this.setting.position.toLowerCase());
  379. if (this.setting.html || this.setting.isHTML) {
  380. /* 内容是html */
  381. $content.innerHTML = content;
  382. }
  383. else {
  384. /* 内容是纯文本 */
  385. $content.innerText = content;
  386. }
  387. if (this.setting.isLimitWidth) {
  388. /* 限制宽度 */
  389. let limitWidthNum = this.setting.limitWidthNum;
  390. if (typeof limitWidthNum === "string") {
  391. if (QmsgUtils.isNumber(limitWidthNum)) {
  392. limitWidthNum = limitWidthNum + "px";
  393. }
  394. }
  395. else {
  396. limitWidthNum = limitWidthNum.toString() + "px";
  397. }
  398. $content.style.maxWidth = limitWidthNum;
  399. $content.style.width = limitWidthNum;
  400. /* 设置换行 */
  401. if (this.setting.limitWidthWrap === "no-wrap") {
  402. /* 禁止换行 */
  403. $content.style.whiteSpace = "nowrap";
  404. }
  405. else if (this.setting.limitWidthWrap === "ellipsis") {
  406. /* 禁止换行且显示省略号 */
  407. $content.style.whiteSpace = "nowrap";
  408. $content.style.overflow = "hidden";
  409. $content.style.textOverflow = "ellipsis";
  410. }
  411. else if (this.setting.limitWidthWrap === "wrap") {
  412. /* 允许换行 */
  413. /* 默认的 */
  414. $content.style.whiteSpace = "";
  415. }
  416. }
  417. this.$Qmsg.innerHTML = /*html*/ `
  418. <div class="qmsg-content">
  419. <div class="${contentClassName}">
  420. ${this.setting.showIcon ? `<i class="qmsg-icon">${$svg}</i>` : ""}
  421. ${$content.outerHTML}
  422. ${$closeIcon}
  423. </div>
  424. </div>
  425. `;
  426. /** 内容容器 */
  427. let $contentContainer = this.$Qmsg.querySelector(".qmsg-content");
  428. this.$Qmsg.classList.add(QmsgUtils.getNameSpacify("item"));
  429. this.$Qmsg.setAttribute(QmsgUtils.getNameSpacify("uuid"), this.uuid);
  430. // 获取页面中的shadowRoot的容器元素
  431. let $shadowContainer = document.querySelector(".qmsg-shadow-container");
  432. let $shadowRoot = $shadowContainer?.shadowRoot;
  433. if (!$shadowContainer) {
  434. // 页面中不存在ShadowRoot容器元素
  435. // 添加新增的ShadowRoot容器元素
  436. $shadowContainer = document.createElement("div");
  437. $shadowContainer.className = "qmsg-shadow-container";
  438. $shadowRoot = $shadowContainer.attachShadow({ mode: "open" });
  439. let __$wrapper__ = document.createElement("div");
  440. __$wrapper__.classList.add(QmsgConfig.NAMESPACE, QmsgUtils.getNameSpacify("wrapper"), QmsgUtils.getNameSpacify("is-initialized"));
  441. __$wrapper__.classList.add($positionClassName);
  442. $shadowRoot.appendChild(QmsgCSS.getStyleElement());
  443. $shadowRoot.appendChild(__$wrapper__);
  444. if (this.setting.style != null) {
  445. // 插入自定义的style
  446. // 这里需要插入到每一条的Qmsg内,以便移除实例时把style也移除
  447. let __$ownStyle__ = document.createElement("style");
  448. __$ownStyle__.setAttribute("type", "text/css");
  449. __$ownStyle__.setAttribute("data-id", this.uuid);
  450. __$ownStyle__.innerHTML = this.setting.style;
  451. $contentContainer.insertAdjacentElement("afterend", __$ownStyle__);
  452. }
  453. document.body.appendChild($shadowContainer);
  454. }
  455. if ($shadowRoot == null) {
  456. throw new TypeError(QmsgConfig.PLUGIN_NAME + " $shadowRoot is null");
  457. }
  458. let $wrapper = $shadowRoot.querySelector(`.${QmsgConfig.NAMESPACE}.${$positionClassName}`);
  459. if (!$wrapper) {
  460. $wrapper = document.createElement("div");
  461. $wrapper.classList.add(QmsgConfig.NAMESPACE, QmsgUtils.getNameSpacify("wrapper"), QmsgUtils.getNameSpacify("is-initialized"));
  462. $wrapper.classList.add($positionClassName);
  463. $shadowRoot.appendChild($wrapper);
  464. }
  465. if (this.setting.showReverse) {
  466. $wrapper.style.flexDirection = "column-reverse";
  467. }
  468. else {
  469. $wrapper.style.flexDirection = "column";
  470. }
  471. let zIndex = this.setting.zIndex;
  472. if (typeof zIndex === "function") {
  473. zIndex = zIndex();
  474. }
  475. if (!isNaN(zIndex)) {
  476. $wrapper.style.zIndex = zIndex.toString();
  477. }
  478. $wrapper.appendChild(this.$Qmsg);
  479. this.setState(this.$Qmsg, "opening");
  480. if (this.setting.showClose) {
  481. /* 关闭按钮绑定点击事件 */
  482. let $closeIcon = this.$Qmsg.querySelector(".qmsg-icon-close");
  483. if ($closeIcon) {
  484. $closeIcon.addEventListener("click", function () {
  485. QmsgContext.close();
  486. });
  487. }
  488. }
  489. /* 监听动画完成 */
  490. let animationendEvent = (event) => {
  491. let animationNameValue = QmsgAnimation.getStyleAnimationNameValue(QmsgContext.$Qmsg);
  492. if (animationNameValue === QmsgAnimation.$state.closing) {
  493. // 当前触发的是关闭
  494. QmsgContext.endTime = Date.now();
  495. QmsgContext.destroy();
  496. }
  497. QmsgAnimation.setStyleAnimationName(QmsgContext.$Qmsg);
  498. };
  499. QmsgAnimation.$name.endNameList.forEach(function (animationendName) {
  500. QmsgContext.$Qmsg.addEventListener(animationendName, animationendEvent);
  501. });
  502. if (this.setting.autoClose) {
  503. /* 自动关闭 */
  504. // 获取时间戳
  505. this.timeId = QmsgUtils.setTimeout(() => {
  506. this.close();
  507. }, this.setting.timeout);
  508. let enterEvent = (event) => {
  509. /* 鼠标滑入,清除定时器,清除开始时间和结束时间 */
  510. this.startTime = null;
  511. this.endTime = null;
  512. QmsgUtils.clearTimeout(this.timeId);
  513. this.timeId = void 0;
  514. };
  515. let leaveEvent = (event) => {
  516. /* 鼠标滑出,重启定时器,创建新的开始时间和timeId */
  517. if (this.timeId != null) {
  518. // 似乎enterEvent函数未正确调用?
  519. console.warn("timeId is not null,mouseenter may be not first trigger");
  520. return;
  521. }
  522. this.startTime = Date.now();
  523. this.timeId = QmsgUtils.setTimeout(() => {
  524. this.close();
  525. }, this.setting.timeout);
  526. };
  527. this.$Qmsg.addEventListener("touchstart", () => {
  528. // 由于移动端不支持mouseout且会触发mouseenter
  529. // 那么需要移除该监听
  530. this.$Qmsg.removeEventListener("mouseenter", enterEvent);
  531. this.$Qmsg.removeEventListener("mouseout", leaveEvent);
  532. }, {
  533. capture: true,
  534. once: true,
  535. });
  536. this.$Qmsg.addEventListener("mouseenter", enterEvent);
  537. this.$Qmsg.addEventListener("mouseout", leaveEvent);
  538. }
  539. }
  540. /**
  541. * 对timeout进行检测并转换
  542. * 当timeout为string时,转换为number
  543. * timeout必须在规定范围内
  544. */
  545. detectionType() {
  546. if (this.setting.timeout != null &&
  547. typeof this.setting.timeout === "string") {
  548. this.setting.timeout = parseInt(this.setting.timeout);
  549. }
  550. if (isNaN(this.setting.timeout)) {
  551. this.setting.timeout = QmsgConfig.DEFAULT.timeout;
  552. }
  553. if (!(this.setting.timeout != null &&
  554. parseInt(this.setting.timeout.toString()) >= 0 &&
  555. parseInt(this.setting.timeout.toString()) <= Number.MAX_VALUE)) {
  556. this.setting.timeout = QmsgConfig.DEFAULT.timeout;
  557. }
  558. if (typeof this.setting.zIndex === "function") {
  559. this.setting.zIndex = this.setting.zIndex();
  560. }
  561. if (this.setting.zIndex != null &&
  562. typeof this.setting.zIndex === "string") {
  563. this.setting.zIndex = parseInt(this.setting.zIndex);
  564. }
  565. if (isNaN(this.setting.zIndex)) {
  566. this.setting.zIndex =
  567. typeof QmsgConfig.DEFAULT.zIndex === "function"
  568. ? QmsgConfig.DEFAULT.zIndex()
  569. : QmsgConfig.DEFAULT.zIndex;
  570. }
  571. }
  572. /**
  573. * 设置元素动画状态 开启/关闭
  574. * @param QmsgMsg
  575. * @param state
  576. */
  577. setState(element, state) {
  578. if (!state || !QmsgAnimation.$state[state])
  579. return;
  580. this.state = state;
  581. QmsgAnimation.setStyleAnimationName(element, QmsgAnimation.$state[state]);
  582. }
  583. /**
  584. * 设置消息数量统计
  585. */
  586. setMsgCount() {
  587. let QmsgContext = this;
  588. let countClassName = QmsgUtils.getNameSpacify("count");
  589. let wrapperClassName = `div.${QmsgUtils.getNameSpacify("data-position", this.setting.position.toLowerCase())} [class^="qmsg-content-"]`;
  590. let $content = this.$Qmsg.querySelector(wrapperClassName);
  591. if (!$content) {
  592. throw new TypeError("$content is null");
  593. }
  594. let $count = $content.querySelector("." + countClassName);
  595. if (!$count) {
  596. $count = document.createElement("span");
  597. $count.classList.add(countClassName);
  598. $content.appendChild($count);
  599. }
  600. $count.innerHTML = this.getRepeatNum().toString();
  601. QmsgAnimation.setStyleAnimationName($count);
  602. QmsgAnimation.setStyleAnimationName($count, "MessageShake");
  603. /* 重置定时器 */
  604. QmsgUtils.clearTimeout(this.timeId);
  605. if (this.setting.autoClose) {
  606. this.timeId = QmsgUtils.setTimeout(function () {
  607. QmsgContext.close();
  608. }, this.setting.timeout);
  609. }
  610. }
  611. /**
  612. * 关闭Qmsg(会触发动画)
  613. */
  614. close() {
  615. this.setState(this.$Qmsg, "closing");
  616. if (QmsgConfig.CAN_ANIMATION) {
  617. /* 支持动画 */
  618. QmsgInstanceStorage.remove(this.uuid);
  619. }
  620. else {
  621. /* 不支持动画 */
  622. this.destroy();
  623. }
  624. let onCloseCallBack = this.setting.onClose;
  625. if (onCloseCallBack && typeof onCloseCallBack === "function") {
  626. onCloseCallBack.call(this);
  627. }
  628. }
  629. /**
  630. * 销毁Qmsg
  631. */
  632. destroy() {
  633. this.endTime = Date.now();
  634. this.$Qmsg.remove();
  635. QmsgUtils.clearTimeout(this.timeId);
  636. QmsgInstanceStorage.remove(this.uuid);
  637. }
  638. /**
  639. * 设置内容文本
  640. */
  641. setText(text) {
  642. let $content = this.$Qmsg.querySelector("div[class^=qmsg-content-] > span");
  643. if ($content) {
  644. $content.innerText = text;
  645. this.setting.content = text;
  646. }
  647. else {
  648. throw new TypeError("$content is null");
  649. }
  650. }
  651. /**
  652. * 设置内容超文本
  653. */
  654. setHTML(text) {
  655. let $content = this.$Qmsg.querySelector("div[class^=qmsg-content-] > span");
  656. if ($content) {
  657. $content.innerHTML = text;
  658. this.setting.content = text;
  659. }
  660. else {
  661. throw new TypeError("$content is null");
  662. }
  663. }
  664. }
  665.  
  666. const createCache = (lastNumberWeakMap) => {
  667. return (collection, nextNumber) => {
  668. lastNumberWeakMap.set(collection, nextNumber);
  669. return nextNumber;
  670. };
  671. };
  672.  
  673. /*
  674. * The value of the constant Number.MAX_SAFE_INTEGER equals (2 ** 53 - 1) but it
  675. * is fairly new.
  676. */
  677. const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER === undefined ? 9007199254740991 : Number.MAX_SAFE_INTEGER;
  678. const TWO_TO_THE_POWER_OF_TWENTY_NINE = 536870912;
  679. const TWO_TO_THE_POWER_OF_THIRTY = TWO_TO_THE_POWER_OF_TWENTY_NINE * 2;
  680. const createGenerateUniqueNumber = (cache, lastNumberWeakMap) => {
  681. return (collection) => {
  682. const lastNumber = lastNumberWeakMap.get(collection);
  683. /*
  684. * Let's try the cheapest algorithm first. It might fail to produce a new
  685. * number, but it is so cheap that it is okay to take the risk. Just
  686. * increase the last number by one or reset it to 0 if we reached the upper
  687. * bound of SMIs (which stands for small integers). When the last number is
  688. * unknown it is assumed that the collection contains zero based consecutive
  689. * numbers.
  690. */
  691. let nextNumber = lastNumber === undefined ? collection.size : lastNumber < TWO_TO_THE_POWER_OF_THIRTY ? lastNumber + 1 : 0;
  692. if (!collection.has(nextNumber)) {
  693. return cache(collection, nextNumber);
  694. }
  695. /*
  696. * If there are less than half of 2 ** 30 numbers stored in the collection,
  697. * the chance to generate a new random number in the range from 0 to 2 ** 30
  698. * is at least 50%. It's benifitial to use only SMIs because they perform
  699. * much better in any environment based on V8.
  700. */
  701. if (collection.size < TWO_TO_THE_POWER_OF_TWENTY_NINE) {
  702. while (collection.has(nextNumber)) {
  703. nextNumber = Math.floor(Math.random() * TWO_TO_THE_POWER_OF_THIRTY);
  704. }
  705. return cache(collection, nextNumber);
  706. }
  707. // Quickly check if there is a theoretical chance to generate a new number.
  708. if (collection.size > MAX_SAFE_INTEGER) {
  709. throw new Error('Congratulations, you created a collection of unique numbers which uses all available integers!');
  710. }
  711. // Otherwise use the full scale of safely usable integers.
  712. while (collection.has(nextNumber)) {
  713. nextNumber = Math.floor(Math.random() * MAX_SAFE_INTEGER);
  714. }
  715. return cache(collection, nextNumber);
  716. };
  717. };
  718.  
  719. const LAST_NUMBER_WEAK_MAP = new WeakMap();
  720. const cache = createCache(LAST_NUMBER_WEAK_MAP);
  721. const generateUniqueNumber = createGenerateUniqueNumber(cache, LAST_NUMBER_WEAK_MAP);
  722.  
  723. const isCallNotification = (message) => {
  724. return message.method !== undefined && message.method === 'call';
  725. };
  726.  
  727. const isClearResponse = (message) => {
  728. return typeof message.id === 'number' && typeof message.result === 'boolean';
  729. };
  730.  
  731. const load = (url) => {
  732. // Prefilling the Maps with a function indexed by zero is necessary to be compliant with the specification.
  733. const scheduledIntervalFunctions = new Map([[0, () => { }]]); // tslint:disable-line no-empty
  734. const scheduledTimeoutFunctions = new Map([[0, () => { }]]); // tslint:disable-line no-empty
  735. const unrespondedRequests = new Map();
  736. const worker = new Worker(url);
  737. worker.addEventListener('message', ({ data }) => {
  738. if (isCallNotification(data)) {
  739. const { params: { timerId, timerType } } = data;
  740. if (timerType === 'interval') {
  741. const idOrFunc = scheduledIntervalFunctions.get(timerId);
  742. if (typeof idOrFunc === undefined) {
  743. throw new Error('The timer is in an undefined state.');
  744. }
  745. if (typeof idOrFunc === 'number') {
  746. const timerIdAndTimerType = unrespondedRequests.get(idOrFunc);
  747. if (timerIdAndTimerType === undefined ||
  748. timerIdAndTimerType.timerId !== timerId ||
  749. timerIdAndTimerType.timerType !== timerType) {
  750. throw new Error('The timer is in an undefined state.');
  751. }
  752. }
  753. else if (typeof idOrFunc === 'function') {
  754. idOrFunc();
  755. }
  756. }
  757. else if (timerType === 'timeout') {
  758. const idOrFunc = scheduledTimeoutFunctions.get(timerId);
  759. if (typeof idOrFunc === undefined) {
  760. throw new Error('The timer is in an undefined state.');
  761. }
  762. if (typeof idOrFunc === 'number') {
  763. const timerIdAndTimerType = unrespondedRequests.get(idOrFunc);
  764. if (timerIdAndTimerType === undefined ||
  765. timerIdAndTimerType.timerId !== timerId ||
  766. timerIdAndTimerType.timerType !== timerType) {
  767. throw new Error('The timer is in an undefined state.');
  768. }
  769. }
  770. else if (typeof idOrFunc === 'function') {
  771. idOrFunc();
  772. // A timeout can be savely deleted because it is only called once.
  773. scheduledTimeoutFunctions.delete(timerId);
  774. }
  775. }
  776. }
  777. else if (isClearResponse(data)) {
  778. const { id } = data;
  779. const timerIdAndTimerType = unrespondedRequests.get(id);
  780. if (timerIdAndTimerType === undefined) {
  781. throw new Error('The timer is in an undefined state.');
  782. }
  783. const { timerId, timerType } = timerIdAndTimerType;
  784. unrespondedRequests.delete(id);
  785. if (timerType === 'interval') {
  786. scheduledIntervalFunctions.delete(timerId);
  787. }
  788. else {
  789. scheduledTimeoutFunctions.delete(timerId);
  790. }
  791. }
  792. else {
  793. const { error: { message } } = data;
  794. throw new Error(message);
  795. }
  796. });
  797. const clearInterval = (timerId) => {
  798. if (typeof scheduledIntervalFunctions.get(timerId) === 'function') {
  799. const id = generateUniqueNumber(unrespondedRequests);
  800. unrespondedRequests.set(id, { timerId, timerType: 'interval' });
  801. scheduledIntervalFunctions.set(timerId, id);
  802. worker.postMessage({
  803. id,
  804. method: 'clear',
  805. params: { timerId, timerType: 'interval' }
  806. });
  807. }
  808. };
  809. const clearTimeout = (timerId) => {
  810. if (typeof scheduledTimeoutFunctions.get(timerId) === 'function') {
  811. const id = generateUniqueNumber(unrespondedRequests);
  812. unrespondedRequests.set(id, { timerId, timerType: 'timeout' });
  813. scheduledTimeoutFunctions.set(timerId, id);
  814. worker.postMessage({
  815. id,
  816. method: 'clear',
  817. params: { timerId, timerType: 'timeout' }
  818. });
  819. }
  820. };
  821. const setInterval = (func, delay = 0, ...args) => {
  822. const timerId = generateUniqueNumber(scheduledIntervalFunctions);
  823. scheduledIntervalFunctions.set(timerId, () => {
  824. func(...args);
  825. // Doublecheck if the interval should still be rescheduled because it could have been cleared inside of func().
  826. if (typeof scheduledIntervalFunctions.get(timerId) === 'function') {
  827. worker.postMessage({
  828. id: null,
  829. method: 'set',
  830. params: {
  831. delay,
  832. now: performance.timeOrigin + performance.now(),
  833. timerId,
  834. timerType: 'interval'
  835. }
  836. });
  837. }
  838. });
  839. worker.postMessage({
  840. id: null,
  841. method: 'set',
  842. params: {
  843. delay,
  844. now: performance.timeOrigin + performance.now(),
  845. timerId,
  846. timerType: 'interval'
  847. }
  848. });
  849. return timerId;
  850. };
  851. const setTimeout = (func, delay = 0, ...args) => {
  852. const timerId = generateUniqueNumber(scheduledTimeoutFunctions);
  853. scheduledTimeoutFunctions.set(timerId, () => func(...args));
  854. worker.postMessage({
  855. id: null,
  856. method: 'set',
  857. params: {
  858. delay,
  859. now: performance.timeOrigin + performance.now(),
  860. timerId,
  861. timerType: 'timeout'
  862. }
  863. });
  864. return timerId;
  865. };
  866. return {
  867. clearInterval,
  868. clearTimeout,
  869. setInterval,
  870. setTimeout
  871. };
  872. };
  873.  
  874. const createLoadOrReturnBroker = (loadBroker, worker) => {
  875. let broker = null;
  876. return () => {
  877. if (broker !== null) {
  878. return broker;
  879. }
  880. const blob = new Blob([worker], { type: 'application/javascript; charset=utf-8' });
  881. const url = URL.createObjectURL(blob);
  882. broker = loadBroker(url);
  883. // Bug #1: Edge up until v18 didn't like the URL to be revoked directly.
  884. setTimeout(() => URL.revokeObjectURL(url));
  885. return broker;
  886. };
  887. };
  888.  
  889. // This is the minified and stringified code of the worker-timers-worker package.
  890. const worker = `(()=>{"use strict";const e=new Map,t=new Map,r=t=>{const r=e.get(t);return void 0!==r&&(clearTimeout(r),e.delete(t),!0)},s=e=>{const r=t.get(e);return void 0!==r&&(clearTimeout(r),t.delete(e),!0)},o=(e,t)=>{const r=performance.now(),s=e+t-r-performance.timeOrigin;return{expected:r+s,remainingDelay:s}},i=(e,t,r,s)=>{const o=r-performance.now();o>0?e.set(t,setTimeout(i,o,e,t,r,s)):(e.delete(t),postMessage({id:null,method:"call",params:{timerId:t,timerType:s}}))};addEventListener("message",(({data:n})=>{try{if("clear"===n.method){const{id:e,params:{timerId:t,timerType:o}}=n;if("interval"===o)postMessage({id:e,result:r(t)});else{if("timeout"!==o)throw new Error('The given type "'.concat(o,'" is not supported'));postMessage({id:e,result:s(t)})}}else{if("set"!==n.method)throw new Error('The given method "'.concat(n.method,'" is not supported'));{const{params:{delay:r,now:s,timerId:a,timerType:m}}=n;if("interval"===m)((t,r,s)=>{const{expected:n,remainingDelay:a}=o(t,s);e.set(r,setTimeout(i,a,e,r,n,"interval"))})(r,a,s);else{if("timeout"!==m)throw new Error('The given type "'.concat(m,'" is not supported'));((e,r,s)=>{const{expected:n,remainingDelay:a}=o(e,s);t.set(r,setTimeout(i,a,t,r,n,"timeout"))})(r,a,s)}}}}catch(e){postMessage({error:{message:e.message},id:n.id,result:null})}}))})();`; // tslint:disable-line:max-line-length
  891.  
  892. const loadOrReturnBroker = createLoadOrReturnBroker(load, worker);
  893. const clearInterval = (timerId) => loadOrReturnBroker().clearInterval(timerId);
  894. const clearTimeout = (timerId) => loadOrReturnBroker().clearTimeout(timerId);
  895. const setInterval = (...args) => loadOrReturnBroker().setInterval(...args);
  896. const setTimeout$1 = (...args) => loadOrReturnBroker().setTimeout(...args);
  897.  
  898. const QmsgUtils = {
  899. /**
  900. * 生成带插件名的名称
  901. * @param args
  902. */
  903. getNameSpacify(...args) {
  904. let result = QmsgConfig.NAMESPACE;
  905. for (let index = 0; index < args.length; ++index) {
  906. result += "-" + args[index];
  907. }
  908. return result;
  909. },
  910. /**
  911. * 判断字符是否是数字
  912. * @param text 需要判断的字符串
  913. */
  914. isNumber(text) {
  915. let isNumberPattern = /^\d+$/;
  916. return isNumberPattern.test(text);
  917. },
  918. /**
  919. * 获取唯一性的UUID
  920. */
  921. getUUID() {
  922. return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (value) {
  923. let randValue = (Math.random() * 16) | 0, newValue = value == "x" ? randValue : (randValue & 0x3) | 0x8;
  924. return newValue.toString(16);
  925. });
  926. },
  927. /**
  928. * 合并参数为配置信息,用于创建Msg实例
  929. * @param content 文本内容
  930. * @param config 配置
  931. */
  932. mergeArgs(content = "", config) {
  933. let opts = {};
  934. if (arguments.length === 0) {
  935. return opts;
  936. }
  937. if (config != null) {
  938. // 传入了2个参数
  939. // string object
  940. // object object
  941. opts.content = content;
  942. if (typeof config === "object" && config != null) {
  943. return Object.assign(opts, config);
  944. }
  945. }
  946. else {
  947. // 传入了1个参数
  948. // object
  949. // string
  950. if (typeof content === "object" && content != null) {
  951. return Object.assign(opts, content);
  952. }
  953. else {
  954. opts.content = content;
  955. }
  956. }
  957. return opts;
  958. },
  959. /**
  960. * 通过配置信息 来判断是否为同一条消息,并返回消息实例
  961. * @param option 配置项
  962. */
  963. judgeReMsg(option) {
  964. option = option || {};
  965. let optionString = JSON.stringify(option);
  966. /* 寻找已生成的实例是否存在配置相同的 */
  967. let findQmsgItemInfo = QmsgInstanceStorage.QmsgList.find((item) => {
  968. return item.config === optionString;
  969. });
  970. let QmsgInstance = findQmsgItemInfo?.instance;
  971. if (QmsgInstance == null) {
  972. /* 不存在,创建个新的 */
  973. let uuid = QmsgUtils.getUUID();
  974. let QmsgItemInfo = {
  975. uuid: uuid,
  976. config: optionString,
  977. instance: new QmsgMsg(option, uuid),
  978. };
  979. QmsgInstanceStorage.QmsgList.push(QmsgItemInfo);
  980. let QmsgListLength = QmsgInstanceStorage.QmsgList.length;
  981. let maxNums = QmsgItemInfo.instance.getSetting().maxNums;
  982. /**
  983. * 关闭多余的消息
  984. */
  985. if (QmsgListLength > maxNums) {
  986. for (let index = 0; index < QmsgListLength - maxNums; index++) {
  987. let item = QmsgInstanceStorage.QmsgList[index];
  988. item && item.instance.getSetting().autoClose && item.instance.close();
  989. }
  990. }
  991. findQmsgItemInfo = QmsgItemInfo;
  992. QmsgInstance = QmsgItemInfo.instance;
  993. }
  994. else {
  995. if (!QmsgInstance.getRepeatNum()) {
  996. QmsgInstance.setRepeatNum(2);
  997. }
  998. else {
  999. if (QmsgInstance.getRepeatNum() >= 99) ;
  1000. else {
  1001. QmsgInstance.setRepeatNumIncreasing();
  1002. }
  1003. }
  1004. QmsgInstance.setMsgCount();
  1005. }
  1006. if (QmsgInstance) {
  1007. QmsgInstance.$Qmsg.setAttribute("data-count", QmsgInstance?.getRepeatNum().toString());
  1008. }
  1009. else {
  1010. throw new TypeError("QmsgInstance is null");
  1011. }
  1012. return QmsgInstance;
  1013. },
  1014. /**
  1015. * 转换为动态对象
  1016. * @param obj 需要配置的对象
  1017. * @param other_obj 获取的其它对象
  1018. */
  1019. toDynamicObject(obj, ...other_objs) {
  1020. let __obj__ = Object.assign({}, obj);
  1021. Object.keys(__obj__).forEach((keyName) => {
  1022. let objValue = __obj__[keyName];
  1023. Object.defineProperty(__obj__, keyName, {
  1024. get() {
  1025. let findIndex = other_objs.findIndex((other_obj) => {
  1026. // 判断其他对象中是否有该属性
  1027. return other_obj.hasOwnProperty.call(other_obj, keyName);
  1028. });
  1029. if (findIndex !== -1) {
  1030. return other_objs[findIndex][keyName];
  1031. }
  1032. else {
  1033. return objValue;
  1034. }
  1035. },
  1036. set(newValue) {
  1037. objValue = newValue;
  1038. },
  1039. });
  1040. });
  1041. return __obj__;
  1042. },
  1043. /**
  1044. * 自动使用 Worker 执行 setTimeout
  1045. */
  1046. setTimeout(callback, timeout) {
  1047. try {
  1048. return setTimeout$1(callback, timeout);
  1049. }
  1050. catch (error) {
  1051. return globalThis.setTimeout(callback, timeout);
  1052. }
  1053. },
  1054. /**
  1055. * 配合 QmsgUtils.setTimeout 使用
  1056. */
  1057. clearTimeout(timeId) {
  1058. try {
  1059. if (timeId != null) {
  1060. clearTimeout(timeId);
  1061. }
  1062. }
  1063. catch (error) {
  1064. }
  1065. finally {
  1066. globalThis.clearTimeout(timeId);
  1067. }
  1068. },
  1069. /**
  1070. * 自动使用 Worker 执行 setInterval
  1071. */
  1072. setInterval(callback, timeout) {
  1073. try {
  1074. return setInterval(callback, timeout);
  1075. }
  1076. catch (error) {
  1077. return globalThis.setInterval(callback, timeout);
  1078. }
  1079. },
  1080. /**
  1081. * 配合 QmsgUtils.setInterval 使用
  1082. */
  1083. clearInterval(timeId) {
  1084. try {
  1085. if (timeId != null) {
  1086. clearInterval(timeId);
  1087. }
  1088. }
  1089. catch (error) {
  1090. }
  1091. finally {
  1092. globalThis.clearInterval(timeId);
  1093. }
  1094. },
  1095. };
  1096.  
  1097. /* 执行兼容 */
  1098. CompatibleProcessing();
  1099. const QmsgEvent = {
  1100. visibilitychange: {
  1101. eventConfig: {
  1102. /**
  1103. * 添加visibilitychange事件监听
  1104. * 当页面切换时,如果切换前的页面存在Qmsg实例且未关闭,切换后,页面活跃度会降低,导致setTimeout/setInterval失效或丢失事件
  1105. * 监听visibilitychange,判断切换回来时,如果当前时间-开始时间大于timeout,则关闭
  1106. * 如果设置了动画,使用close,否则使用destroy
  1107. */
  1108. callback() {
  1109. if (document.visibilityState === "visible") {
  1110. // 回到页面
  1111. for (let index = 0; index < QmsgInstanceStorage.QmsgList.length; index++) {
  1112. let QmsgInstance = QmsgInstanceStorage.QmsgList[index];
  1113. if (QmsgInstance.instance.endTime == null &&
  1114. QmsgInstance.instance.startTime != null &&
  1115. Date.now() - QmsgInstance.instance.startTime >=
  1116. QmsgInstance.instance.getSetting().timeout) {
  1117. // 超出时间,关闭
  1118. QmsgInstance.instance.close();
  1119. }
  1120. }
  1121. }
  1122. },
  1123. option: {
  1124. capture: true,
  1125. },
  1126. },
  1127. addEvent() {
  1128. if ("visibilityState" in document) {
  1129. document.addEventListener("visibilitychange", QmsgEvent.visibilitychange.eventConfig.callback, QmsgEvent.visibilitychange.eventConfig.option);
  1130. }
  1131. else {
  1132. console.error("visibilityState not support");
  1133. }
  1134. },
  1135. removeEvent() {
  1136. document.removeEventListener("visibilitychange", QmsgEvent.visibilitychange.eventConfig.callback, QmsgEvent.visibilitychange.eventConfig.option);
  1137. },
  1138. },
  1139. };
  1140. class Qmsg {
  1141. /** 数据 */
  1142. $data;
  1143. $eventUtils;
  1144. constructor() {
  1145. this.$data = {
  1146. version: "2024.12.6",
  1147. config: QmsgConfig,
  1148. icon: QmsgIcon,
  1149. instanceStorage: QmsgInstanceStorage,
  1150. };
  1151. this.$eventUtils = QmsgEvent;
  1152. this.$eventUtils.visibilitychange.addEvent();
  1153. }
  1154. /**
  1155. * 修改默认配置
  1156. * @param option
  1157. */
  1158. config(option) {
  1159. if (option == null)
  1160. return;
  1161. if (typeof option !== "object")
  1162. return;
  1163. QmsgConfig.INS_DEFAULT = null;
  1164. QmsgConfig.INS_DEFAULT = option;
  1165. }
  1166. info(content, option) {
  1167. let params = QmsgUtils.mergeArgs(content, option);
  1168. params.type = "info";
  1169. return QmsgUtils.judgeReMsg.call(this, params);
  1170. }
  1171. warning(content, option) {
  1172. let params = QmsgUtils.mergeArgs(content, option);
  1173. params.type = "warning";
  1174. return QmsgUtils.judgeReMsg.call(this, params);
  1175. }
  1176. success(content, option) {
  1177. let params = QmsgUtils.mergeArgs(content, option);
  1178. params.type = "success";
  1179. return QmsgUtils.judgeReMsg.call(this, params);
  1180. }
  1181. error(content, option) {
  1182. let params = QmsgUtils.mergeArgs(content, option);
  1183. params.type = "error";
  1184. return QmsgUtils.judgeReMsg.call(this, params);
  1185. }
  1186. loading(content, config) {
  1187. let params = QmsgUtils.mergeArgs(content, config);
  1188. params.type = "loading";
  1189. params.autoClose = false;
  1190. return QmsgUtils.judgeReMsg.call(this, params);
  1191. }
  1192. /**
  1193. * 根据uuid删除Qmsg实例和元素
  1194. * @param uuid
  1195. */
  1196. remove(uuid) {
  1197. QmsgInstanceStorage.remove(uuid);
  1198. }
  1199. /**
  1200. * 关闭当前Qmsg创建的所有的实例
  1201. */
  1202. closeAll() {
  1203. for (let index = QmsgInstanceStorage.QmsgList.length - 1; index >= 0; index--) {
  1204. let item = QmsgInstanceStorage.QmsgList[index];
  1205. item && item.instance && item.instance.close();
  1206. }
  1207. }
  1208. }
  1209. let qmsg = new Qmsg();
  1210.  
  1211. return qmsg;
  1212.  
  1213. }));
  1214. //# sourceMappingURL=index.umd.js.map