You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带触摸功能的笔记本无法显示自定义Cursor的问题求助

解决方案

核心思路是通过事件触发顺序判断设备类型:优先响应触摸事件标记为纯触摸设备,响应鼠标事件则标记为支持鼠标的设备(包括带触摸的笔记本),以此区分显示/隐藏自定义光标。

步骤1:修改CSS初始状态

初始隐藏自定义光标,默认光标设为常规样式,仅当检测到鼠标设备时再隐藏默认光标:

html, body, html *, body * {
    cursor: default;
}

.cursor-dot-outline {
    pointer-events: none;
    position: fixed;
    top: 50%;
    left: 50%;
    border-radius: 50%;
    opacity: 0;
    transform: translate(-50%, -50%);
    transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
}
.cursor-dot {
    width: 8px;
    height: 8px;
    background-color: transparent;
    z-index: 99999;
}
.cursor-dot-outline {
    width: 40px;
    height: 40px;
    background-color: transparent;
    border: 2px solid #b560d5;
    z-index: 99999;
}

步骤2:修改JavaScript逻辑

添加设备状态标记,通过一次性事件监听判断设备类型,再动态绑定/移除事件:

$(document).ready(function () {
    var cursor = {
        delay: 4,
        _x: 0,
        _y: 0,
        endX: (window.innerWidth / 2),
        endY: (window.innerHeight / 2),
        cursorVisible: false,
        cursorEnlarged: false,
        isMouseDevice: false,
        isTouchDevice: false,
        $dot: document.querySelector('.cursor-dot'),
        $outline: document.querySelector('.cursor-dot-outline'),
        handleMouseMove: null,
        handleMouseEnter: null,
        handleMouseLeave: null,

        init: function () {
            this.dotSize = this.$dot.offsetWidth;
            this.outlineSize = this.$outline.offsetWidth;
            this.setupDeviceDetection();
            this.animateDotOutline();
        },

        setupDeviceDetection: function () {
            var self = this;

            // 优先检测触摸事件:标记为纯触摸设备,隐藏自定义光标
            document.addEventListener('touchstart', function() {
                self.isTouchDevice = true;
                self.isMouseDevice = false;
                self.cursorVisible = false;
                self.toggleCursorVisibility();
                document.documentElement.style.cursor = 'default';
                
                // 移除鼠标事件监听(如果已绑定)
                if (self.handleMouseMove) document.removeEventListener('mousemove', self.handleMouseMove);
                if (self.handleMouseEnter) document.removeEventListener('mouseenter', self.handleMouseEnter);
                if (self.handleMouseLeave) document.removeEventListener('mouseleave', self.handleMouseLeave);
            }, { once: true });

            // 检测第一次鼠标移动:标记为鼠标设备,启用自定义光标
            document.addEventListener('mousemove', function handleFirstMouseMove() {
                if (!self.isTouchDevice) {
                    self.isMouseDevice = true;
                    self.cursorVisible = true;
                    self.toggleCursorVisibility();
                    document.documentElement.style.cursor = 'none';
                    self.bindMouseEvents();
                    document.removeEventListener('mousemove', handleFirstMouseMove);
                }
            }, { once: true });
        },

        bindMouseEvents: function() {
            var self = this;
            const CLICKABLE_ELEMENTS = 'a, button, select, .filter-boolean';

            // 可点击元素的光标缩放事件
            document.querySelectorAll(CLICKABLE_ELEMENTS).forEach(function (el) {
                el.addEventListener('mouseover', function () {
                    self.cursorEnlarged = true;
                    self.toggleCursorSize();
                });
                el.addEventListener('mouseout', function () {
                    self.cursorEnlarged = false;
                    self.toggleCursorSize();
                });
            });

            // 鼠标点击的光标缩放事件
            document.addEventListener('mousedown', function () {
                self.cursorEnlarged = true;
                self.toggleCursorSize();
            });
            document.addEventListener('mouseup', function () {
                self.cursorEnlarged = false;
                self.toggleCursorSize();
            });

            // 鼠标移动事件
            self.handleMouseMove = function(e) {
                self.cursorVisible = true;
                self.toggleCursorVisibility();
                self.endX = e.clientX;
                self.endY = e.clientY;
                self.$dot.style.top = self.endY + 'px';
                self.$dot.style.left = self.endX + 'px';
            };
            document.addEventListener('mousemove', self.handleMouseMove);

            // 鼠标进入/离开页面事件
            self.handleMouseEnter = function() {
                self.cursorVisible = true;
                self.toggleCursorVisibility();
                self.$dot.style.opacity = 1;
                self.$outline.style.opacity = 1;
            };
            document.addEventListener('mouseenter', self.handleMouseEnter);

            self.handleMouseLeave = function() {
                self.cursorVisible = false;
                self.toggleCursorVisibility();
                self.$dot.style.opacity = 0;
                self.$outline.style.opacity = 0;
            };
            document.addEventListener('mouseleave', self.handleMouseLeave);
        },

        animateDotOutline: function () {
            var self = this;
            self._x += (self.endX - self._x) / self.delay;
            self._y += (self.endY - self._y) / self.delay;
            self.$outline.style.top = self._y + 'px';
            self.$outline.style.left = self._x + 'px';
            requestAnimationFrame(this.animateDotOutline.bind(self));
        },

        toggleCursorSize: function () {
            var self = this;
            if (self.cursorEnlarged) {
                self.$dot.style.transform = 'translate(-50%, -50%) scale(0.75)';
                self.$outline.style.transform = 'translate(-50%, -50%) scale(1.5)';
            } else {
                self.$dot.style.transform = 'translate(-50%, -50%) scale(1)';
                self.$outline.style.transform = 'translate(-50%, -50%) scale(1)';
            }
        },

        toggleCursorVisibility: function () {
            var self = this;
            if (self.cursorVisible) {
                self.$dot.style.opacity = 1;
                self.$outline.style.opacity = 1;
            } else {
                self.$dot.style.opacity = 0;
                self.$outline.style.opacity = 0;
            }
        }
    }

    cursor.init();
});

关键逻辑说明

  1. 设备检测优先级:先监听touchstart事件,一旦触发则判定为纯触摸设备(手机、iPad),直接隐藏自定义光标并恢复默认光标。
  2. 鼠标设备判定:仅当未触发触摸事件时,响应第一次mousemove事件,判定为支持鼠标的设备(桌面、带触摸的笔记本),启用自定义光标并绑定所有鼠标交互事件。
  3. 事件一次性监听:设备类型仅判断一次,避免重复触发逻辑,提升性能。
  4. 修复原代码bug:修正mouseleave事件中错误的cursorVisible赋值,确保离开页面时隐藏自定义光标。

内容的提问来源于stack exchange,提问作者Phillip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 12:19:53