Message

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

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