带触摸功能的笔记本无法显示自定义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(); });
关键逻辑说明
- 设备检测优先级:先监听
touchstart事件,一旦触发则判定为纯触摸设备(手机、iPad),直接隐藏自定义光标并恢复默认光标。 - 鼠标设备判定:仅当未触发触摸事件时,响应第一次
mousemove事件,判定为支持鼠标的设备(桌面、带触摸的笔记本),启用自定义光标并绑定所有鼠标交互事件。 - 事件一次性监听:设备类型仅判断一次,避免重复触发逻辑,提升性能。
- 修复原代码bug:修正
mouseleave事件中错误的cursorVisible赋值,确保离开页面时隐藏自定义光标。
内容的提问来源于stack exchange,提问作者Phillip
相关产品推荐
相关产品推荐

