init project
This commit is contained in:
120
src/utils/directives/Popup.ts
Normal file
120
src/utils/directives/Popup.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import type { Directive, DirectiveBinding } from "vue";
|
||||
import Toolkit from "../Toolkit";
|
||||
|
||||
export enum PopupType {
|
||||
TEXT,
|
||||
IMG,
|
||||
HTML,
|
||||
EL
|
||||
}
|
||||
|
||||
/** */
|
||||
export type PopupConfig = {
|
||||
|
||||
type: PopupType,
|
||||
value?: string | HTMLElement;
|
||||
canShow?: () => boolean;
|
||||
beforeShow?: (type: PopupType, value: string | HTMLElement) => Promise<void>;
|
||||
afterHidden?: (type: PopupType, value: string | HTMLElement) => Promise<void>;
|
||||
}
|
||||
|
||||
// Popup 弹出提示 DOM 节点,全局唯一
|
||||
let popup: HTMLElement | null;
|
||||
|
||||
const VPopup: Directive = {
|
||||
|
||||
mounted(el: HTMLElement, binding: DirectiveBinding<PopupConfig>) {
|
||||
// 转配置
|
||||
let config: PopupConfig;
|
||||
if (binding.arg && binding.arg === "config") {
|
||||
config = binding.value as PopupConfig;
|
||||
} else {
|
||||
config = {
|
||||
type: PopupType.TEXT,
|
||||
value: binding.value as any as string,
|
||||
canShow: () => true
|
||||
};
|
||||
}
|
||||
// Popup 节点
|
||||
if (!popup) {
|
||||
popup = document.getElementById("tui-popup");
|
||||
}
|
||||
let isShowing = false;
|
||||
// 显示
|
||||
el.addEventListener("mouseenter", async e => {
|
||||
if (!config.value) {
|
||||
console.warn("not found popup value", config);
|
||||
return;
|
||||
}
|
||||
if (config.beforeShow) {
|
||||
await config.beforeShow(config.type, config.value);
|
||||
}
|
||||
if (config.canShow && config.canShow() && popup) {
|
||||
let el: HTMLElement | null = null;
|
||||
if (!config) {
|
||||
el = document.createElement("div");
|
||||
el.className = "text";
|
||||
el.textContent = config as string;
|
||||
popup.appendChild(el);
|
||||
}
|
||||
switch (config.type) {
|
||||
case PopupType.TEXT:
|
||||
// 文本
|
||||
el = document.createElement("div");
|
||||
el.className = "text";
|
||||
el.textContent = config.value as string;
|
||||
popup.appendChild(el);
|
||||
break;
|
||||
case PopupType.IMG:
|
||||
// 图片
|
||||
el = document.createElement("img");
|
||||
(el as HTMLImageElement).src = config.value as string;
|
||||
popup.appendChild(el);
|
||||
break;
|
||||
case PopupType.HTML:
|
||||
// HTML 字符串
|
||||
popup.appendChild(Toolkit.toDOM(config.value as string));
|
||||
break;
|
||||
case PopupType.EL:
|
||||
// DOM 节点
|
||||
if (config.value instanceof HTMLElement) {
|
||||
const valueEl = config.value as HTMLElement;
|
||||
valueEl.style.display = "block";
|
||||
popup.appendChild(valueEl);
|
||||
break;
|
||||
} else {
|
||||
console.error(config);
|
||||
throw new Error("Vue 指令错误:v-popup:el 的值不是 HTML 元素");
|
||||
}
|
||||
}
|
||||
popup.style.left = (e.x + 20) + "px";
|
||||
popup.style.top = (e.y + 14) + "px";
|
||||
popup.style.visibility = "visible";
|
||||
isShowing = true;
|
||||
}
|
||||
}, false);
|
||||
// 移动
|
||||
el.addEventListener("mousemove", async (e) => {
|
||||
if (config.canShow && config.canShow() && isShowing && popup) {
|
||||
popup.style.left = (e.x + 20) + "px";
|
||||
popup.style.top = (e.y + 14) + "px";
|
||||
}
|
||||
}, false);
|
||||
// 隐藏
|
||||
el.addEventListener("mouseleave", async () => {
|
||||
if (popup) {
|
||||
popup.style.visibility = "hidden";
|
||||
popup.innerText = "";
|
||||
popup.style.left = "0px";
|
||||
popup.style.top = "0px";
|
||||
|
||||
// 隐藏后事件
|
||||
if (config.afterHidden && config.value) {
|
||||
await config.afterHidden(config.type, config.value);
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
};
|
||||
|
||||
export default VPopup;
|
||||
Reference in New Issue
Block a user