JavaScript实现网格项自定义光标跟随鼠标的问题求助
JavaScript实现网格项自定义光标跟随鼠标的问题求助
嘿,我看了你的代码,马上就发现两个问题的根源啦,咱们一个个来解决:
问题1:所有光标同时移动的原因
你现在把aimX和aimY设成了全局变量,所有光标动画都在共用这两个值。所以不管你移动到哪个网格项,所有光标都会朝着同一个目标坐标移动。
解决办法是:把目标坐标和每个光标绑定在一起,不让它们共用全局变量,比如把动画逻辑和每个网格项直接绑定。
问题2:光标和鼠标距离过大的原因
你的自定义光标是相对于父元素.grid__item(它是position:relative)定位的,但你用了event.pageX和event.pageY(相对于整个文档的坐标)来设置left和top,这就导致坐标系统不匹配,光标自然就跑偏了。应该用event.offsetX和event.offsetY(相对于当前网格项的坐标)。
修正后的完整代码
HTML(和你的代码一致,无需修改)
<div class="grid"> <div class="grid__item js-post"> <div class="grid__item-number">1</div> <div class="grid__item-cursor js-cursor">Read more</div> </div> <div class="grid__item js-post"> <div class="grid__item-number">2</div> <div class="grid__item-cursor js-cursor">Read more</div> </div> <div class="grid__item js-post"> <div class="grid__item-number">3</div> <div class="grid__item-cursor js-cursor">Read more</div> </div> <div class="grid__item js-post"> <div class="grid__item-number">4</div> <div class="grid__item-cursor js-cursor">Read more</div> </div> <div class="grid__item js-post"> <div class="grid__item-number">5</div> <div class="grid__item-cursor js-cursor">Read more</div> </div> <div class="grid__item js-post"> <div class="grid__item-number">6</div> <div class="grid__item-cursor js-cursor">Read more</div> </div> <div class="grid__item js-post"> <div class="grid__item-number">7</div> <div class="grid__item-cursor js-cursor">Read more</div> </div> <div class="grid__item js-post"> <div class="grid__item-number">8</div> <div class="grid__item-cursor js-cursor">Read more</div> </div> </div>
CSS(新增了几个体验优化)
body { font-family: "helvetica", arial, sans-serif; } .grid { display: grid; width: 100%; grid-template-columns: repeat(4, 1fr); grid-column-gap: 1rem; grid-row-gap: 1rem; } .grid__item { display: flex; justify-content: center; align-content: center; position: relative; padding: 25%; overflow: hidden; background-color: #333; cursor: none; /* 隐藏系统默认鼠标,提升自定义光标体验 */ } .grid__item-number { color: #888; font-size: 5rem; } .grid__item-cursor { position: absolute; top: 0; left: 0; padding: 0.25em; background-color: red; opacity: 0; /* 默认隐藏,避免初始状态显示 */ pointer-events: none; /* 防止光标元素干扰鼠标事件 */ transition: opacity 0.2s ease; /* 显示隐藏加过渡更平滑 */ } .grid__item-cursor.is-visible { background-color: yellow; opacity: 1; }
JavaScript(核心逻辑重构)
const posts = document.querySelectorAll(".js-post"); posts.forEach((post) => { const cursor = post.querySelector(".js-cursor"); // 每个光标独享自己的目标和当前坐标,不再用全局变量 let aimX = 0; let aimY = 0; let currentX = 0; let currentY = 0; const speed = 0.2; const animate = function () { currentX += (aimX - currentX) * speed; currentY += (aimY - currentY) * speed; cursor.style.left = currentX + "px"; cursor.style.top = currentY + "px"; requestAnimationFrame(animate); }; // 每个光标启动独立的动画循环 animate(); post.addEventListener("mousemove", function (event) { // 用offsetX/Y获取相对于当前网格项的坐标,匹配光标定位逻辑 aimX = event.offsetX; aimY = event.offsetY; }); post.addEventListener("mouseenter", function () { cursor.classList.add("is-visible"); }); post.addEventListener("mouseleave", function () { cursor.classList.remove("is-visible"); }); });
改动核心说明
- 独立动画上下文:每个网格项的光标都有自己的目标坐标和动画变量,再也不会出现所有光标同步移动的问题。
- 坐标系统匹配:改用
offsetX/Y获取鼠标在当前网格项内的相对位置,光标终于能精准跟着鼠标走了。 - 体验细节优化:隐藏系统鼠标、防止光标干扰事件、添加过渡动画,让整体交互更流畅自然。
这样修改后,你的两个问题应该都能完美解决啦!
备注:内容来源于stack exchange,提问作者Mathieu Préaud
相关产品推荐
相关产品推荐

