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

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");
  });
});

改动核心说明

  1. 独立动画上下文:每个网格项的光标都有自己的目标坐标和动画变量,再也不会出现所有光标同步移动的问题。
  2. 坐标系统匹配:改用offsetX/Y获取鼠标在当前网格项内的相对位置,光标终于能精准跟着鼠标走了。
  3. 体验细节优化:隐藏系统鼠标、防止光标干扰事件、添加过渡动画,让整体交互更流畅自然。

这样修改后,你的两个问题应该都能完美解决啦!

备注:内容来源于stack exchange,提问作者Mathieu Préaud

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 10:39:33