import Vue from "vue"; import { computePosition, offset, flip, shift, arrow } from "@floating-ui/dom"; let tooltipNode = null; let intervalId = null; function removeTooltip() { try { intervalId && clearInterval(intervalId); tooltipNode && document.body.removeChild(tooltipNode); } catch (e) { // console.log( // "尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:", // e // ); } } Vue.directive("tooltip", { bind: function (el, binding) { if (!binding.value) { return; } el.addEventListener( "mouseenter", function (e) { tooltipNode = document.createElement("div"); tooltipNode.style.position = "fixed"; tooltipNode.style.zIndex = 2147483647; tooltipNode.style.backgroundColor = "#191A1C"; tooltipNode.style.border = "1px solid rgba(151, 151, 151, 0.2)"; tooltipNode.style.borderRadius = "3px"; tooltipNode.style.border = "1px solid rgba(151, 151, 151, 0.2)"; tooltipNode.style.boxShadow = "0px 2px 12px 0px rgba(0, 0, 0, 0.06)"; tooltipNode.style.padding = "8px 8px"; tooltipNode.style.fontSize = "12px"; tooltipNode.style.cursor = "default"; tooltipNode.style.pointerEvents = "none"; tooltipNode.style.wordBreak = "keep-all"; tooltipNode.style.whiteSpace = "pre"; tooltipNode.style.fontSize = "12px"; tooltipNode.style.lineHeight = "17px"; tooltipNode.style.color = "rgba(255, 255, 255, 0.6)"; tooltipNode.innerText = binding.value; const arrowNode = document.createElement("div"); arrowNode.style.position = "absolute"; arrowNode.style.backgroundColor = "inherit"; arrowNode.style.boxSizing = "border-box"; arrowNode.style.width = "12px"; arrowNode.style.height = "12px"; arrowNode.style.border = "1px solid transparent"; arrowNode.style.borderRight = "inherit"; arrowNode.style.borderBottom = "inherit"; arrowNode.style.transform = "rotate(45deg)"; tooltipNode.appendChild(arrowNode); document.body.appendChild(tooltipNode); computePosition(el, tooltipNode, { placement: "top", middleware: [ offset(13), flip(), shift({ padding: 12 }), arrow({ element: arrowNode, padding: 3, }), ], }) .then(({ x, y, placement, middlewareData }) => { Object.assign(tooltipNode.style, { left: `${x}px`, top: `${y}px`, }); const { x: arrowX, y: arrowY } = middlewareData.arrow; const staticSide = { top: "bottom", right: "left", bottom: "top", left: "right", }[placement.split("-")[0]]; Object.assign(arrowNode.style, { left: arrowX != null ? `${arrowX}px` : "", [staticSide]: "-6px", }); }) .catch((err) => { console.log( "计算tooltip位置时出现异常,可能因为目标元素已经被卸载。" ); }); intervalId = setInterval(() => { if (!document.contains(el)) { removeTooltip(); } }, 300); }, { passive: false, } ); el.addEventListener("mouseleave", removeTooltip); el.addEventListener("mousedown", removeTooltip); el.addEventListener("keydown", removeTooltip); el.addEventListener("scroll", removeTooltip); el.addEventListener("dragstart", removeTooltip); el.addEventListener("dragstart", removeTooltip); el.addEventListener("dragleave", removeTooltip); }, });