【JS/TS鼠标气泡跟随】文本提示 / 操作提示

适用于任何类型项目:vue、react、angular、js、ts、jsp、jquery


1、功能封装:

TypeScript 复制代码
export function useMouseActionTip(text: string, parentEl: HTMLElement, offset?: XY) {
    function mousemove(e: MouseEvent) {
        const offsetX = offset?.x || 16;
        const offsetY = offset?.y || 16;
        cursorEl.style.left = e.pageX + offsetX + "px";
        cursorEl.style.top = e.pageY + offsetY + "px";
    }
    function mouseenter() {
        cursorEl.style.display = "block";
    }
    function mouseout() {
        cursorEl.style.display = "none";
    }
    const cursorEl = document.createElement("div");
    cursorEl.className = "_mouse_action_tip";
    cursorEl.innerHTML = text;
    cursorEl.style.display = "block";

    setStyle();
    document.body.appendChild(cursorEl);
    document.addEventListener("mousemove", mousemove);
    parentEl.addEventListener("mouseenter", mouseenter);
    parentEl.addEventListener("mouseout", mouseout);

    return {
        destroy() {
            document.removeEventListener("mousemove", mousemove);
            setStyle();
            parentEl.removeEventListener("mouseenter", mouseenter);
            parentEl.removeEventListener("mouseout", mouseout);
            document.body.removeChild(cursorEl);
        },
    };
}
export type UseMouseActionTip = ReturnType<typeof useMouseActionTip>;
let hasStyle = false;
function setStyle() {
    if (hasStyle) {
        return;
    }
    hasStyle = true;
    const styleElement = document.createElement("style");
    styleElement.textContent = `
    ._mouse_action_tip {
        position: fixed;
        display: flex;
        padding: 5px 10px;
        background-color: #33383e;
        color: #e8eaec;
        border-radius: 4px;
        pointer-events: none;
        z-index: 9999;
        box-shadow: rgba(255, 255, 255, 0.3) 0px 0px 3px, rgba(255, 255, 255, 0.3) 0px 0px 3px;
        font-size: 14px;
      }
    `;
    document.head.appendChild(styleElement);
}

2、使用:

TypeScript 复制代码
let mouseTip: UseMouseActionTip | undefined;
watch(
    () => editorStore.currentSubTool,
    () => {
            if (editorStore.currentSubTool === SubTools.Measure) {
                mouseTip = useMouseActionTip(
                    t("Editor.Tip.Hold_down_and_drag_the_mouse"),
                    editorStore.canvas().canvas.upperCanvasEl
                );
            } else {
                mouseTip?.destroy();
                mouseTip = undefined;
            }
    }
);
相关推荐
Hilaku4 分钟前
2025快手直播至暗时刻:当黑产自动化洪流击穿P0防线,我们前端能做什么?🤷‍♂️
前端·javascript·安全
San30.4 分钟前
深度解析 React 组件化开发:从 Props 通信到样式管理的进阶指南
前端·javascript·react.js
C_心欲无痕5 分钟前
vue3 - 内置组件KeepAlive优化组件状态缓存
前端·vue.js·缓存
Swift社区8 分钟前
跨端路由设计:如何统一 RN 与 Web 的页面模型
前端·react.js·web3
fantasy_arch13 分钟前
SVT-AV1帧类型决策-场景切换检测
前端·网络·av1
LYFlied13 分钟前
前端工程化核心面试题与详解
前端·面试·工程化
小程故事多_8029 分钟前
用Agent与大模型实现Web项目全自动化生成:从需求到部署的完整落地方案
运维·前端·人工智能·自动化·aigc
千里马-horse32 分钟前
AsyncContext
开发语言·前端·javascript·c++·napi·asynccontext
勇往直前plus33 分钟前
Jackson 反序列化首字母大写字段映射失败的底层原因与解决方案
java·开发语言·前端
转转技术团队33 分钟前
基于微前端 qiankun 多实例保活的工程实践
前端·javascript·前端工程化