| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- import { usezIndex } from "./vue/hooks";
- /**
- * 消息提醒功能
- * @param params
- */
- function useMessage(params = {}) {
- const doc = document;
- const cssModule = `__${Math.random().toString(36).slice(2, 7)}`;
- const className = {
- box: `msg-box${cssModule}`,
- hide: `hide${cssModule}`,
- text: `msg-text${cssModule}`,
- icon: `msg-icon${cssModule}`
- };
- const style = doc.createElement("style");
- style.textContent = `
- .${className.box}, .${className.icon}, .${className.text} {
- padding: 0;
- margin: 0;
- box-sizing: border-box;
- }
- .${className.box} {
- position: fixed;
- top: 0;
- left: 50%;
- display: flex;
- padding: 12px 16px;
- border-radius: 2px;
- background-color: #fff;
- box-shadow: 0 3px 3px -2px rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.14),0 1px 8px 0 rgba(0,0,0,.12);
- white-space: nowrap;
- animation: ${className.box}-move .4s;
- transition: .4s all;
- transform: translate3d(-50%, 0%, 0);
- opacity: 1;
- overflow: hidden;
- }
- .${className.box}::after {
- content: "";
- position: absolute;
- left: 0;
- top: 0;
- height: 100%;
- width: 4px;
- }
- @keyframes ${className.box}-move {
- 0% {
- opacity: 0;
- transform: translate3d(-50%, -100%, 0);
- }
- 100% {
- opacity: 1;
- transform: translate3d(-50%, 0%, 0);
- }
- }
- .${className.box}.${className.hide} {
- opacity: 0;
- /* transform: translate3d(-50%, -100%, 0); */
- transform: translate3d(-50%, -100%, 0) scale(0);
- }
- .${className.icon} {
- display: inline-block;
- width: 18px;
- height: 18px;
- border-radius: 50%;
- overflow: hidden;
- margin-right: 6px;
- position: relative;
- }
- .${className.text} {
- font-size: 14px;
- line-height: 18px;
- color: #555;
- }
- .${className.icon}::after,
- .${className.icon}::before {
- position: absolute;
- content: "";
- background-color: #fff;
- }
- .${className.box}.info .${className.icon}, .${className.box}.info::after {
- background-color: #1890ff;
- }
- .${className.box}.success .${className.icon}, .${className.box}.success::after {
- background-color: #52c41a;
- }
- .${className.box}.warning .${className.icon}, .${className.box}.warning::after {
- background-color: #faad14;
- }
- .${className.box}.error .${className.icon}, .${className.box}.error::after {
- background-color: #ff4d4f;
- }
- .${className.box}.info .${className.icon}::after,
- .${className.box}.warning .${className.icon}::after {
- top: 15%;
- left: 50%;
- margin-left: -1px;
- width: 2px;
- height: 2px;
- border-radius: 50%;
- }
- .${className.box}.info .${className.icon}::before,
- .${className.box}.warning .${className.icon}::before {
- top: calc(15% + 4px);
- left: 50%;
- margin-left: -1px;
- width: 2px;
- height: 40%;
- }
- .${className.box}.error .${className.icon}::after,
- .${className.box}.error .${className.icon}::before {
- top: 20%;
- left: 50%;
- width: 2px;
- height: 60%;
- margin-left: -1px;
- border-radius: 1px;
- }
- .${className.box}.error .${className.icon}::after {
- transform: rotate(-45deg);
- }
- .${className.box}.error .${className.icon}::before {
- transform: rotate(45deg);
- }
- .${className.box}.success .${className.icon}::after {
- box-sizing: content-box;
- background-color: transparent;
- border: 2px solid #fff;
- border-left: 0;
- border-top: 0;
- height: 50%;
- left: 35%;
- top: 13%;
- transform: rotate(45deg);
- width: 20%;
- transform-origin: center;
- }
- `.replace(/(\n|\t|\s)*/ig, "$1").replace(/\n|\t|\s(\{|\}|\,|\:|\;)/ig, "$1").replace(/(\{|\}|\,|\:|\;)\s/ig, "$1");
- doc.head.appendChild(style);
- /** 消息队列 */
- const messageList = [];
- /**
- * 获取指定`item`的定位`top`
- * @param el
- */
- function getItemTop(el) {
- let top = 10;
- for (let i = 0; i < messageList.length; i++) {
- const item = messageList[i];
- if (el && el === item) {
- break;
- }
- top += item.clientHeight + 20;
- }
- return top;
- }
- /**
- * 删除指定列表项
- * @param el
- */
- function removeItem(el) {
- for (let i = 0; i < messageList.length; i++) {
- const item = messageList[i];
- if (item === el) {
- messageList.splice(i, 1);
- break;
- }
- }
- el.classList.add(className.hide);
- messageList.forEach(function (item) {
- item.style.top = `${getItemTop(item)}px`;
- });
- }
- /**
- * 显示一条消息
- * @param content 内容
- * @param type 消息类型
- * @param duration 持续时间,优先级比默认值高
- */
- function show(content, type = "info", duration) {
- const el = doc.createElement("div");
- el.className = `${className.box} ${type}`;
- el.style.top = `${getItemTop()}px`;
- el.style.zIndex = zIndex.message;
- el.innerHTML = `
- <span class="${className.icon}"></span>
- <span class="${className.text}">${content}</span>
- `;
- messageList.push(el);
- doc.body.appendChild(el);
- // 添加动画监听事件
- function animationEnd() {
- el.removeEventListener("animationend", animationEnd);
- setTimeout(removeItem, duration || params.duration || 3000, el);
- }
- el.addEventListener("animationend", animationEnd);
- function transitionEnd() {
- if (getComputedStyle(el).opacity !== "0")
- return;
- el.removeEventListener("transitionend", transitionEnd);
- el.remove();
- }
- el.addEventListener("transitionend", transitionEnd);
- }
- return {
- show,
- /** 普通描述提示 */
- info(msg) {
- show(msg, "info");
- },
- /** 成功提示 */
- success(msg) {
- show(msg, "success");
- },
- /** 警告提示 */
- warning(msg) {
- show(msg, "warning");
- },
- /** 错误提示 */
- error(msg) {
- show(msg, "error");
- }
- };
- }
- /** 对话框控件 */
- function useDialog() {
- const doc = document;
- const cssModule = `__${Math.random().toString(36).slice(2, 7)}`;
- const className = {
- mask: `dialog-mask${cssModule}`,
- popup: `dialog-popup${cssModule}`,
- title: `dialog-title${cssModule}`,
- content: `dialog-content${cssModule}`,
- footer: `dialog-footer${cssModule}`,
- confirm: `confirm${cssModule}`,
- fade: `fade${cssModule}`,
- show: `show${cssModule}`,
- hide: `hide${cssModule}`
- };
- const cssText = `
- .${className.mask} {
- --time: .3s;
- --transition: .3s all;
- --black: #333;
- --text-color: #555;
- --confirm-bg: #2ec1cb;
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0,0,0,0.45);
- display: flex;
- align-items: center;
- justify-content: center;
- transition: var(--transition);
- animation: ${className.fade} var(--time);
- }
- .${className.mask} * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- .${className.popup} {
- width: 74%;
- max-width: 375px;
- border-radius: var(--border-radius);
- box-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 3px 1px -2px rgba(0, 0, 0, 0.12);
- background-color: #fff;
- transition: var(--transition);
- animation: ${className.show} var(--time);
- }
- .${className.title} {
- font-size: 18px;
- padding: 12px 15px;
- border-bottom: solid 1px #eee;
- font-weight: normal;
- color: var(--black);
- text-align: left;
- }
- .${className.content} {
- padding: 16px 15px;
- font-size: 15px;
- color: var(--text-color);
- text-align: left;
- }
- .${className.footer} {
- width: 100%;
- text-align: right;
- border-top: solid 1px #eee;
- padding: 12px 15px;
- }
- @keyframes ${className.fade} {
- 0% { opacity: 0; }
- 100% { opacity: 1; }
- }
- @keyframes ${className.show} {
- 0% { transform: translate3d(var(--x), var(--y), 0) scale(0); }
- 100% { transform: translate3d(0, 0, 0) scale(1); }
- }
- .${className.mask}.${className.hide} {
- opacity: 0;
- }
- .${className.mask}.${className.hide} .${className.popup} {
- transform: translate3d(var(--x), var(--y), 0) scale(0);
- }
- `;
- const style = doc.createElement("style");
- style.textContent = cssText.replace(/(\n|\t|\s)*/ig, "$1").replace(/\n|\t|\s(\{|\}|\,|\:|\;)/ig, "$1").replace(/(\{|\}|\,|\:|\;)\s/ig, "$1");
- doc.head.appendChild(style);
- /** 点击记录坐标 */
- const clickSize = {
- x: "0vw",
- y: "0vh"
- };
- // 添加点击事件,并记录每次点击坐标
- doc.addEventListener("click", function (e) {
- const { innerWidth, innerHeight } = window;
- const centerX = innerWidth / 2;
- const centerY = innerHeight / 2;
- const pageY = e.clientY - centerY;
- const pageX = e.clientX - centerX;
- clickSize.x = `${pageX / innerWidth * 100}vw`;
- clickSize.y = `${pageY / innerHeight * 100}vh`;
- }, true);
- /**
- * 输出节点
- * @param option
- */
- function show(option) {
- const el = doc.createElement("section");
- el.className = className.mask;
- el.style.zIndex = zIndex.dialog;
- // 设置起始偏移位置
- el.style.setProperty("--x", clickSize.x);
- el.style.setProperty("--y", clickSize.y);
- // 设置完之后还原坐标位置
- clickSize.x = "0vw";
- clickSize.y = "0vh";
- const cancelBtn = option.cancelText ? `<button class="the-btn">${option.cancelText}</button>` : "";
- el.innerHTML = `
- <div class="${className.popup}">
- <h2 class="${className.title}">${typeof option.title === "string" ? option.title : "提示"}</h2>
- <div class="${className.content}">${option.content}</div>
- <div class="${className.footer}">
- ${cancelBtn}
- <button class="${className.confirm} the-btn blue">${option.confirmText || "确认"}</button>
- </div>
- </div>
- `;
- doc.body.appendChild(el);
- el.addEventListener("transitionend", function (e) {
- e.target === el && el.classList.contains(className.hide) && el.remove();
- });
- function hide() {
- el.classList.add(className.hide);
- }
- if (option.cancelText) {
- el.querySelector(`.${className.footer} button`).onclick = function () {
- hide();
- option.cancel && option.cancel();
- };
- }
- el.querySelector(`.${className.confirm}`).onclick = function () {
- hide();
- option.confirm && option.confirm();
- };
- }
- return {
- show
- };
- }
- const zIndex = {
- get message() {
- return (usezIndex() + 20).toString();
- },
- get dialog() {
- return (usezIndex() + 10).toString();
- }
- };
- /** 顶部消息提醒控件 */
- export const message = useMessage({
- duration: 3600
- });
- const dialog = useDialog();
- /** 对话弹框控件 */
- export const messageBox = dialog.show;
|