Message

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

当前为 2023-05-19 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/462234/1192786/Message.js

  1. /*
  2. * @Date: 2022-11-18 13:38:41
  3. * @LastEditors: WhiteSev 893177236@qq.com
  4. * @LastEditTime: 2023-05-19 18:35:46
  5. * @原地址: https://www.jq22.com/jquery-info23550
  6. * @说明: 修改config配置{"position":"topleft|top|topright|centerleft|center|centerright|bottomleft|bottomright|bottom"} 九宫格,
  7. * 九个位置弹出,修改原center为显示中间,top代替原center
  8. * @说明: 新增config配置{"contentWrap":true},长文本全部显示(支持换行),默认为false
  9. * @说明: 新增config配置{"showIcon":true},可关闭左边的图标
  10. */
  11. (function (root, Msg) {
  12. if (typeof exports === "object" && typeof module !== "undefined") {
  13. module.exports = Msg;
  14. } else if (typeof define === "function" && define.amd) {
  15. define([], function () {
  16. return Msg(root);
  17. });
  18. } else {
  19. root.Qmsg = Msg(root);
  20. }
  21. })(this, function (global) {
  22. "use strict";
  23.  
  24. /* assign 兼容处理 */
  25. if (typeof Object.assign != "function") {
  26. Object.assign = function (target) {
  27. if (target == null) {
  28. throw new TypeError("Cannot convert undefined or null to object");
  29. }
  30. target = Object(target);
  31. for (var index = 1; index < arguments.length; index++) {
  32. var source = arguments[index];
  33. if (source != null) {
  34. for (var key in source) {
  35. if (Object.prototype.hasOwnProperty.call(source, key)) {
  36. target[key] = source[key];
  37. }
  38. }
  39. }
  40. }
  41. return target;
  42. };
  43. }
  44.  
  45. /* 'classList' 兼容处理,add,remove不支持传入多个cls参数 */
  46. if (!("classList" in document.documentElement)) {
  47. Object.defineProperty(HTMLElement.prototype, "classList", {
  48. get: function () {
  49. var self = this;
  50.  
  51. function update(fn) {
  52. return function (value) {
  53. var classes = self.className.split(/\s+/g),
  54. index = classes.indexOf(value);
  55. fn(classes, index, value);
  56. self.className = classes.join(" ");
  57. };
  58. }
  59. return {
  60. add: update(function (classes, index, value) {
  61. if (!~index) classes.push(value);
  62. }),
  63.  
  64. remove: update(function (classes, index) {
  65. if (~index) classes.splice(index, 1);
  66. }),
  67.  
  68. toggle: update(function (classes, index, value) {
  69. if (~index) classes.splice(index, 1);
  70. else classes.push(value);
  71. }),
  72.  
  73. contains: function (value) {
  74. return !!~self.className.split(/\s+/g).indexOf(value);
  75. },
  76.  
  77. item: function (i) {
  78. return self.className.split(/\s+/g)[i] || null;
  79. },
  80. };
  81. },
  82. });
  83. }
  84.  
  85. /**
  86. * 声明插件名称
  87. */
  88. var PLUGIN_NAME = "qmsg";
  89.  
  90. /**
  91. * 命名空间 用于css和事件
  92. */
  93. var NAMESPACE =
  94. (global && global.QMSG_GLOBALS && global.QMSG_GLOBALS.NAMESPACE) ||
  95. PLUGIN_NAME;
  96.  
  97. /**
  98. * 状态 & 动画
  99. * 显示中,显示完成,关闭中
  100. */
  101. var STATES = {
  102. opening: "MessageMoveIn",
  103. done: "",
  104. closing: "MessageMoveOut",
  105. };
  106.  
  107. /**
  108. * 全局默认配置
  109. * 可在引入js之前通过QMSG_GLOBALS.DEFAULTS进行配置
  110. * position {String} 位置,仅支持'center','right','left',默认'center'
  111. * showReverse {Boolean} 弹出顺序是否逆反,true|false,默认false
  112. * showMoreContent {Boolean} 是否使内容进行换行显示,true|false,默认false
  113. * showIcon {Boolean} 是否显示左边的icon图标, true|false,默认true
  114. * type {String} 类型,支持'info','warning','success','error','loading'
  115. * showClose {Boolean} 是否显示关闭图标,默认为false不显示
  116. * timeout {Number} 多久后自动关闭,单位ms,默认2500
  117. * autoClose {Boolean} 是否自动关闭,默认true,注意在type为loading的时候自动关闭为false
  118. * content {String} 提示的内容
  119. * onClose {Function} 关闭的回调函数
  120. */
  121. var DEFAULTS = Object.assign(
  122. {
  123. animation: true,
  124. autoClose: true,
  125. content: "",
  126. html: false,
  127. position: "top",
  128. showClose: false,
  129. maxNums: 5,
  130. onClose: null,
  131. showIcon: true,
  132. showMoreContent: false,
  133. showReverse: false,
  134. timeout: 2500,
  135. type: "info",
  136. },
  137. global && global.QMSG_GLOBALS && global.QMSG_GLOBALS.DEFAULTS
  138. );
  139.  
  140. /**
  141. * 设置icon html代码
  142. */
  143. var ICONS = {
  144. 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>',
  145. warning:
  146. '<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>',
  147. error:
  148. '<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>',
  149. success:
  150. '<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>',
  151. loading:
  152. '<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>',
  153. close:
  154. '<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>',
  155. };
  156.  
  157. /**
  158. * 是否支持动画属性
  159. * @type {Boolean}
  160. */
  161. var CAN_ANIMATION = (function () {
  162. var style = document.createElement("div").style;
  163. return (
  164. style.animationName !== undefined ||
  165. style.WebkitAnimationName !== undefined ||
  166. style.MozAnimationName !== undefined ||
  167. style.msAnimationName !== undefined ||
  168. style.OAnimationName !== undefined
  169. );
  170. })();
  171.  
  172. /**
  173. * 生成带插件名的名称
  174. * @param {...String}
  175. * @returns {String}
  176. */
  177. function namespacify() {
  178. var res = NAMESPACE;
  179. for (var i = 0; i < arguments.length; ++i) {
  180. res += "-" + arguments[i];
  181. }
  182. return res;
  183. }
  184.  
  185. /**
  186. * 获取唯一性的UUID
  187. * @returns String
  188. */
  189. function getUUID() {
  190. return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
  191. /[xy]/g,
  192. function (value) {
  193. let randValue = (Math.random() * 16) | 0,
  194. newValue = value == "x" ? randValue : (randValue & 0x3) | 0x8;
  195. return newValue.toString(16);
  196. }
  197. );
  198. }
  199. /**
  200. * 每条消息的构造函数
  201. * @param {Objetc} opts 配置参数,参考DEFAULTS
  202. */
  203. function Msg(opts, uuid) {
  204. var oMsg = this;
  205. oMsg.settings = Object.assign({}, DEFAULTS, opts || {});
  206. oMsg.uuid = uuid;
  207. var timeout = oMsg.settings.timeout;
  208. timeout =
  209. timeout &&
  210. parseInt(timeout >= 0) &&
  211. parseInt(timeout) <= Math.NEGATIVE_INFINITY
  212. ? parseInt(timeout)
  213. : DEFAULTS.timeout;
  214. oMsg.timeout = timeout;
  215. oMsg.settings.timeout = timeout;
  216. oMsg.timer = null;
  217. var $elem = document.createElement("div");
  218. var $svg = ICONS[oMsg.settings.type || "info"];
  219. var contentClassName = namespacify(
  220. "content-" + oMsg.settings.type || "info"
  221. );
  222. contentClassName += oMsg.settings.showClose
  223. ? " " + namespacify("content-with-close")
  224. : "";
  225. var content = oMsg.settings.content || "";
  226. var contentStyle = "";
  227. var $closeIconStyle = "";
  228. var $closeSvg = ICONS["close"];
  229. if (oMsg.settings.showMoreContent) {
  230. contentStyle = `
  231. display: flex;
  232. align-items: center;
  233. white-space: unset;
  234. overflow: unset;
  235. text-overflow: unset;
  236. padding-right: unset;
  237. `;
  238. $closeIconStyle = `
  239. position:unset;
  240. overflow:unset;
  241. padding-left: 6px;
  242. margin-right: 0px;
  243. `;
  244. }
  245. var $closeIcon = oMsg.settings.showClose
  246. ? `<i class="qmsg-icon qmsg-icon-close" style="${$closeIconStyle}">${$closeSvg}</i>`
  247. : "";
  248. var $span = document.createElement("span");
  249. var $positionClassName = namespacify(
  250. "data-position",
  251. oMsg.settings.position.toLowerCase()
  252. );
  253. if (oMsg.settings.html) {
  254. $span.innerHTML = content;
  255. } else {
  256. $span.innerText = content;
  257. }
  258. $elem.innerHTML = `
  259. <div class="qmsg-content">
  260. <div class="${contentClassName}" style="${contentStyle}">
  261. ${oMsg.settings.showIcon ? `<i class="qmsg-icon">${$svg}</i>` : ""}
  262. ${$span.outerHTML}
  263. ${$closeIcon}
  264. </div>
  265. </div>
  266. `;
  267. $elem.classList.add(namespacify("item"));
  268. var $wrapper = document.querySelector(
  269. `.${NAMESPACE}.${$positionClassName}`
  270. );
  271. if (!$wrapper) {
  272. /* 不存在就添加 */
  273. $wrapper = document.createElement("div");
  274. $wrapper.classList.add(
  275. NAMESPACE,
  276. namespacify("wrapper"),
  277. namespacify("is-initialized")
  278. );
  279. $wrapper.classList.add($positionClassName);
  280. document.body.appendChild($wrapper);
  281. }
  282. if (oMsg.settings.showReverse) {
  283. $wrapper.style.flexDirection = "column-reverse";
  284. } else {
  285. $wrapper.style.flexDirection = "column";
  286. }
  287.  
  288. $wrapper.appendChild($elem);
  289. oMsg.$wrapper = $wrapper;
  290. oMsg.$elem = $elem;
  291. setState(oMsg, "opening");
  292. if (oMsg.settings.showClose) {
  293. // 关闭按钮绑定点击事件
  294. $elem.querySelector(".qmsg-icon-close").addEventListener(
  295. "click",
  296. function () {
  297. oMsg.close();
  298. }.bind($elem)
  299. );
  300. }
  301. $elem.addEventListener(
  302. "animationend",
  303. function (event) {
  304. // 监听动画完成
  305. var target = event.target,
  306. animationName = event.animationName;
  307. if (animationName === STATES["closing"]) {
  308. clearInterval(this.timer);
  309. this.destroy();
  310. }
  311. target.style.animationName = "";
  312. }.bind(oMsg)
  313. );
  314. if (oMsg.settings.autoClose) {
  315. // 自动关闭
  316. setTimeout(function() {
  317. this.close();
  318. }.bind(oMsg), this.timeout);
  319. /* 重复调用会导致this.timeout时间会自动更新,会不及时关闭 */
  320. /* var intvMs = 10; // 定时器频率
  321. oMsg.timer = setInterval(
  322. function () {
  323. this.timeout -= intvMs;
  324. if (this.timeout <= 0) {
  325. clearInterval(this.timer);
  326. this.close();
  327. }
  328. }.bind(oMsg),
  329. intvMs
  330. ); */
  331. oMsg.$elem.addEventListener(
  332. "mouseover",
  333. function () {
  334. clearInterval(this.timer);
  335. }.bind(oMsg)
  336. );
  337. oMsg.$elem.addEventListener(
  338. "mouseout",
  339. function () {
  340. if (this.state !== "closing") {
  341. /* 状态为关闭则不重启定时器 */
  342. setTimeout(function() {
  343. this.close();
  344. }.bind(oMsg), this.timeout);
  345. /* this.timer = setInterval(
  346. function () {
  347. this.timeout -= intvMs;
  348. if (this.timeout <= 0) {
  349. clearInterval(this.timer);
  350. this.close();
  351. }
  352. }.bind(oMsg),
  353. intvMs
  354. ); */
  355. }
  356. }.bind(oMsg)
  357. );
  358. }
  359. }
  360.  
  361. /* 设置元素动画状态 开启/关闭 */
  362. function setState(inst, state) {
  363. if (!state || !STATES[state]) return;
  364. inst.state = state;
  365. inst.$elem.style.animationName = STATES[state];
  366. }
  367.  
  368. /**
  369. * 直接销毁元素,不会触发关闭回调函数
  370. */
  371. Msg.prototype.destroy = function () {
  372. this.$elem.parentNode && this.$elem.parentNode.removeChild(this.$elem);
  373. clearInterval(this.timer);
  374. Qmsg.remove(this.uuid);
  375. };
  376. /**
  377. * 关闭,支持动画则会触发动画事件
  378. */
  379. Msg.prototype.close = function () {
  380. setState(this, "closing");
  381. if (!CAN_ANIMATION) {
  382. /* 不支持动画 */
  383. this.destroy();
  384. } else {
  385. Qmsg.remove(this.uuid);
  386. }
  387. var callback = this.settings.onClose;
  388. if (callback && callback instanceof Function) {
  389. callback.call(this);
  390. }
  391. };
  392.  
  393. /**
  394. * 修改已创建元素内容
  395. * @param {String} text 文本
  396. */
  397. Msg.prototype.setText = function (text) {
  398. this.$elem.querySelector("div[class^=qmsg-content-] > span").innerText =
  399. text;
  400. this.settings.content = text;
  401. };
  402.  
  403. /**
  404. * 修改已创建元素内容
  405. * @param {String} text html文本
  406. */
  407. Msg.prototype.setHTML = function (text) {
  408. this.$elem.querySelector("div[class^=qmsg-content-] > span").innerHTML =
  409. text;
  410. this.settings.content = text;
  411. };
  412. /**
  413. * 设置消息数量统计
  414. * @private
  415. */
  416. function setMsgCount(oMsg) {
  417. var countClassName = namespacify("count");
  418. var wrapperClassName = `div.${namespacify(
  419. "data-position",
  420. oMsg.settings.position.toLowerCase()
  421. )} [class^="qmsg-content-"]`;
  422. var $content = oMsg.$elem.querySelector(wrapperClassName),
  423. $count = $content.querySelector("." + countClassName);
  424. if (!$count) {
  425. $count = document.createElement("span");
  426. $count.classList.add(countClassName);
  427. $content.appendChild($count);
  428. }
  429. $count.innerHTML = oMsg.count;
  430. $count.style.animationName = "";
  431. $count.style.animationName = "MessageShake";
  432. oMsg.timeout = oMsg.settings.timeout || DEFAULTS.timeout;
  433. }
  434.  
  435. /**
  436. * 合并参数为配置信息,用于创建Msg实例
  437. * @param {String} txt 文本内容
  438. * @param {Object} config 配置
  439. * @private
  440. */
  441. function mergeArgs(txt, config) {
  442. var opts = Object.assign({}, DEFAULTS);
  443. if (arguments.length === 0) {
  444. return opts;
  445. }
  446. if (txt instanceof Object) {
  447. return Object.assign(opts, txt);
  448. } else {
  449. opts.content = txt.toString();
  450. }
  451. if (config instanceof Object) {
  452. return Object.assign(opts, config);
  453. }
  454. return opts;
  455. }
  456.  
  457. /**
  458. * 通过配置信息 来判断是否为同一条消息,并返回消息实例
  459. * @param {Object} params 配置项
  460. * @private
  461. */
  462. function judgeReMsg(params) {
  463. params = params || {};
  464. var opt = JSON.stringify(params);
  465. var oMsg = null;
  466. /* 寻找已生成的实例是否存在配置相同的 */
  467. var oMsgsIndex;
  468. for (oMsgsIndex in this.oMsgs) {
  469. if (this.oMsgs[oMsgsIndex].config === opt) {
  470. oMsg = this.oMsgs[oMsgsIndex].inst;
  471. break;
  472. }
  473. }
  474. if (oMsg == null) {
  475. /* 不存在,创建个新的 */
  476. var oMsgUUID = getUUID();
  477. var oItem = {};
  478. oItem.uuid = oMsgUUID;
  479. oItem.config = opt;
  480. oMsg = new Msg(params, oMsgUUID);
  481. oMsg.uuid = oMsgUUID;
  482. oMsg.count = "";
  483. oItem.inst = oMsg;
  484. this.oMsgs = [...this.oMsgs, oItem];
  485. var len = this.oMsgs.length;
  486. var maxNums = this.maxNums;
  487. /**
  488. * 关闭多余的消息
  489. */
  490. if (len > maxNums) {
  491. var oIndex = 0;
  492. var oMsgs = this.oMsgs;
  493. for (oIndex; oIndex < len - maxNums; oIndex++) {
  494. oMsgs[oIndex] &&
  495. oMsgs[oIndex].inst.settings.autoClose &&
  496. oMsgs[oIndex].inst.close();
  497. }
  498. }
  499. } else {
  500. oMsg.count = !oMsg.count
  501. ? 2
  502. : oMsg.count >= 99
  503. ? oMsg.count
  504. : oMsg.count + 1;
  505. setMsgCount(oMsg);
  506. }
  507. oMsg.$elem.setAttribute("data-count", oMsg.count);
  508. return oMsg;
  509. }
  510.  
  511. var Qmsg = {
  512. version: "0.0.2" /* 版本 */,
  513. oMsgs: [] /* 实例数组 */,
  514. maxNums: DEFAULTS.maxNums || 5 /* 最大数量 */,
  515. config: function (cfg) {
  516. DEFAULTS =
  517. cfg && cfg instanceof Object ? Object.assign(DEFAULTS, cfg) : DEFAULTS;
  518. this.maxNums =
  519. DEFAULTS.maxNums && DEFAULTS.maxNums > 0
  520. ? parseInt(DEFAULTS.maxNums)
  521. : 3;
  522. } /* 配置 */,
  523. info: function (txt, config) {
  524. var params = mergeArgs(txt, config);
  525. params.type = "info";
  526. return judgeReMsg.call(this, params);
  527. },
  528. warning: function (txt, config) {
  529. var params = mergeArgs(txt, config);
  530. params.type = "warning";
  531. return judgeReMsg.call(this, params);
  532. },
  533. success: function (txt, config) {
  534. var params = mergeArgs(txt, config);
  535. params.type = "success";
  536. return judgeReMsg.call(this, params);
  537. },
  538. error: function (txt, config) {
  539. var params = mergeArgs(txt, config);
  540. params.type = "error";
  541. return judgeReMsg.call(this, params);
  542. },
  543. loading: function (txt, config) {
  544. var params = mergeArgs(txt, config);
  545. params.type = "loading";
  546. params.autoClose = false;
  547. return judgeReMsg.call(this, params);
  548. },
  549. remove: function (uuid) {
  550. this.oMsgs.forEach((item, index) => {
  551. if (item.uuid === uuid) {
  552. this.oMsgs.splice(index, 1);
  553. return;
  554. }
  555. });
  556. },
  557. closeAll: function () {
  558. /* 使用splice会改变数组长度,先获取长度 */
  559. let oMsgsLength = this.oMsgs.length;
  560. for (let i = 0; i < oMsgsLength; i++) {
  561. this.oMsgs[0] && this.oMsgs[0].inst.close();
  562. }
  563. },
  564. };
  565.  
  566. var PLUGIN_CSS = {
  567. css: `@charset "utf-8";
  568. .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;}
  569. .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%);}
  570. .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);}
  571. .qmsg.qmsg-data-position-bottomleft .qmsg-item,.qmsg.qmsg-data-position-left .qmsg-item,.qmsg.qmsg-data-position-topleft .qmsg-item{text-align:left;}
  572. .qmsg.qmsg-data-position-bottom .qmsg-item,.qmsg.qmsg-data-position-center .qmsg-item,.qmsg.qmsg-data-position-top .qmsg-item{text-align:center;}
  573. .qmsg.qmsg-data-position-bottomright .qmsg-item,.qmsg.qmsg-data-position-right .qmsg-item,.qmsg.qmsg-data-position-topright .qmsg-item{text-align:right;}
  574. .qmsg .qmsg-item{position:relative;padding:8px;text-align:center;-webkit-animation-duration:.3s;animation-duration:.3s;}
  575. .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;}
  576. .qmsg .qmsg-item:first-child{margin-top:-8px;}
  577. .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;}
  578. .qmsg .qmsg-content [class^=qmsg-content-]{display:flex;align-items:center;}
  579. .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;}
  580. .qmsg .qmsg-icon svg{display:inline-block;}
  581. .qmsg .qmsg-content-info .qmsg-icon{color:#1890ff;}
  582. .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;}
  583. .qmsg .qmsg-icon-close:hover>svg path{stroke:#555;}
  584. .qmsg .animate-turn{animation:MessageTurn 1s linear infinite;-webkit-animation:MessageTurn 1s linear infinite;}
  585. @keyframes MessageTurn{0%{-webkit-transform:rotate(0);}
  586. 25%{-webkit-transform:rotate(90deg);}
  587. 50%{-webkit-transform:rotate(180deg);}
  588. 75%{-webkit-transform:rotate(270deg);}
  589. 100%{-webkit-transform:rotate(360deg);}
  590. }
  591. @-webkit-keyframes MessageTurn{0%{-webkit-transform:rotate(0);}
  592. 25%{-webkit-transform:rotate(90deg);}
  593. 50%{-webkit-transform:rotate(180deg);}
  594. 75%{-webkit-transform:rotate(270deg);}
  595. 100%{-webkit-transform:rotate(360deg);}
  596. }
  597. @-webkit-keyframes MessageMoveOut{0%{max-height:150px;opacity:1;}
  598. to{max-height:0;opacity:0;}
  599. }
  600. @keyframes MessageMoveOut{0%{max-height:150px;opacity:1;}
  601. to{max-height:0;opacity:0;}
  602. }
  603. @-webkit-keyframes MessageMoveIn{0%{opacity:0;transform:translateY(-100%);transform-origin:0 0;}
  604. to{opacity:1;transform:translateY(0);transform-origin:0 0;}
  605. }
  606. @keyframes MessageMoveIn{0%{opacity:0;transform:translateY(-100%);transform-origin:0 0;}
  607. to{opacity:1;transform:translateY(0);transform-origin:0 0;}
  608. }
  609. @-webkit-keyframes MessageShake{0%,100%{opacity:1;transform:translateX(0);}
  610. 25%,75%{opacity:.75;transform:translateX(-4px);}
  611. 50%{opacity:.25;transform:translateX(4px);}
  612. }
  613. @keyframes MessageShake{0%,100%{opacity:1;transform:translateX(0);}
  614. 25%,75%{opacity:.75;transform:translateX(-4px);}
  615. 50%{opacity:.25;transform:translateX(4px);}
  616. }`,
  617. init() {
  618. let cssResourceNode = document.createElement("style");
  619. cssResourceNode.setAttribute("type", "text/css");
  620. cssResourceNode.setAttribute("data-insert-from", "qmsg");
  621. cssResourceNode.innerHTML = this.css;
  622. if (document.head) {
  623. document.head.append(cssResourceNode);
  624. } else if (document.documentElement) {
  625. if (document.documentElement.childNodes.length === 0) {
  626. document.documentElement.appendChild(cssResourceNode);
  627. } else {
  628. document.documentElement.insertBefore(
  629. cssResourceNode,
  630. document.documentElement.childNodes[
  631. document.documentElement.childNodes.length - 1
  632. ]
  633. );
  634. }
  635. } else {
  636. throw new Error("未找到可以插入到页面中的元素");
  637. }
  638. },
  639. };
  640. PLUGIN_CSS.init();
  641. return Qmsg;
  642. });