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

Vue3中如何让目标元素在复合函数内跟随鼠标移动?

实现Vue3(Nuxt+VueUse)元素跟随鼠标移动的最优方案

原代码问题分析

  1. 直接修改style无效:目标元素未设置position属性(如absolute/fixed),left/top样式仅对定位元素生效;且useMouseInElement返回的是鼠标在目标元素内部的坐标,而非视口全局坐标,用于定位会导致位置偏移。
  2. anime.js方案异常:每次鼠标移动都创建新的动画实例,多个动画同时执行会导致冲突,出现卡顿、位置跳变等问题。

最优方案:纯VueUse+原生样式(轻量高效)

无需额外依赖,直接通过VueUse获取鼠标坐标,结合定位样式实现流畅跟随,还可按需添加居中逻辑提升体验。

优化后的复合函数

import { onMounted } from 'vue';
import { useMouse, useEventListener } from '@vueuse/core';

export function useStickToMouse(target) {
  onMounted(() => {
    if (!target.value) return;
    
    // 获取视口内的鼠标坐标
    const { x: mouseX, y: mouseY } = useMouse();
    // 计算元素中心偏移量(让鼠标对准元素中心)
    const rect = target.value.getBoundingClientRect();
    const offsetX = rect.width / 2;
    const offsetY = rect.height / 2;

    function moveTarget() {
      // 更新元素定位
      target.value.style.left = `${mouseX.value - offsetX}px`;
      target.value.style.top = `${mouseY.value - offsetY}px`;
    }

    // 绑定鼠标移动事件
    useEventListener(window, 'mousemove', moveTarget);
    // 初始位置直接定位到鼠标处
    moveTarget();
  });
}

跟随组件实现(添加定位样式)

<template>
  <div ref="target" class="follow-mouse-wrapper">
    <slot></slot>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { useStickToMouse } from '@/composables/useStickToMouse';

const target = ref(null);
useStickToMouse(target);
</script>

<style scoped>
.follow-mouse-wrapper {
  position: fixed; /* 根据需求切换为absolute */
  pointer-events: none; /* 可选:避免元素遮挡鼠标事件,需要交互则删除 */
}
</style>

使用方式

<follow-mouse-wrapper>
  <component-to-move></component-to-move>
</follow-mouse-wrapper>

可选:平滑跟随(基于VueUse过渡)

如果需要平滑移动效果,推荐使用VueUse的useTransition替代anime.js,避免动画堆积:

import { onMounted, computed, watch } from 'vue';
import { useMouse, useTransition } from '@vueuse/core';

export function useStickToMouse(target) {
  onMounted(() => {
    if (!target.value) return;
    
    const { x: mouseX, y: mouseY } = useMouse();
    const rect = target.value.getBoundingClientRect();
    const offsetX = rect.width / 2;
    const offsetY = rect.height / 2;

    // 计算目标位置
    const targetX = computed(() => mouseX.value - offsetX);
    const targetY = computed(() => mouseY.value - offsetY);

    // 启用平滑过渡
    const [x, y] = useTransition([targetX, targetY], {
      duration: 100,
      easing: 'easeOutQuad'
    });

    // 监听过渡值更新样式
    watch([x, y], ([newX, newY]) => {
      target.value.style.left = `${newX}px`;
      target.value.style.top = `${newY}px`;
    });
  });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 22:58:37