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

如何在Vue.js站点中实现元素堆叠上升的拼贴动效?

Vue.js 实现鼠标跟随流体光晕动效方案

你提到的动效本质是基于Canvas渲染的鼠标交互效果,核心是鼠标移动时生成跟随的渐变光晕,搭配背景悬浮粒子的联动效果,在Vue项目中可以参考以下两种实现方案:

方案1:基于轻量动效库快速实现(适配Vue3)

适合需要快速上线、不需要高度自定义的场景,使用@tsparticles/vue3实现:

  • 第一步安装依赖:npm install @tsparticles/vue3 @tsparticles/slim
  • 第二步在入口文件注册插件:
import { createApp } from 'vue'
import App from './App.vue'
import Particles from "@tsparticles/vue3";
import { loadSlim } from "@tsparticles/slim";

const app = createApp(App)
app.use(Particles, {
  init: async (engine) => {
    await loadSlim(engine);
  }
})
app.mount('#app')
  • 第三步在需要增加动效的页面组件中调用:
<template>
  <div class="page-wrapper">
    <VueParticles id="particle-canvas" :options="particleConfig" />
    <!-- 页面内容层级要高于Canvas,避免被遮挡 -->
    <div class="page-content">
      你的站点原有内容
    </div>
  </div>
</template>

<script setup>
const particleConfig = {
  interactivity: {
    events: {
      onHover: {
        enable: true,
        mode: "grab"
      }
    },
    modes: {
      grab: {
        distance: 140,
        links: {
          opacity: 0.2
        }
      }
    }
  },
  particles: {
    color: {
      value: "#6366f1" // 可替换为你站点的主色调
    },
    links: {
      color: "#6366f1",
      distance: 150,
      enable: true,
      opacity: 0.1,
      width: 1
    },
    move: {
      enable: true,
      speed: { min: 1, max: 3 },
    },
    opacity: {
      value: { min: 0.1, max: 0.5 }
    },
    size: {
      value: { min: 1, max: 3 }
    }
  },
  background: {
    color: "#0f172a" // 和你站点背景色保持一致即可
  }
}
</script>

<style scoped>
.page-wrapper {
  position: relative;
  min-height: 100vh;
}
#particle-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
}
.page-content {
  position: relative;
  z-index: 1;
}
</style>

方案2:原生Canvas手写实现(无额外依赖,性能更高)

适合需要高度自定义动效参数的场景,核心逻辑如下:

<template>
  <div class="canvas-wrapper">
    <canvas ref="canvasRef" id="mouse-effect"></canvas>
    <div class="page-content">你的站点原有内容</div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

const canvasRef = ref(null)
let ctx = null
let animationId = null
// 鼠标参数配置
let mouse = { x: 0, y: 0, radius: 150 }
let particles = []

// 粒子类
class Particle {
  constructor() {
    this.x = Math.random() * window.innerWidth
    this.y = Math.random() * window.innerHeight
    this.size = Math.random() * 3 + 1
    this.speedX = Math.random() * 1 - 0.5
    this.speedY = Math.random() * 1 - 0.5
  }
  update() {
    this.x += this.speedX
    this.y += this.speedY
    // 粒子边界回弹逻辑
    if (this.x < 0 || this.x > window.innerWidth) this.speedX *= -1
    if (this.y < 0 || this.y > window.innerHeight) this.speedY *= -1
    // 计算鼠标距离,靠近时放大
    const dx = this.x - mouse.x
    const dy = this.y - mouse.y
    const distance = Math.sqrt(dx * dx + dy * dy)
    this.size = distance < mouse.radius ? Math.min(8, this.size + 0.3) : Math.max(1, this.size - 0.1)
  }
  draw() {
    ctx.fillStyle = 'rgba(99, 102, 241, 0.6)'
    ctx.beginPath()
    ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2)
    ctx.fill()
  }
}

// 初始化Canvas
const initCanvas = () => {
  const canvas = canvasRef.value
  ctx = canvas.getContext('2d')
  canvas.width = window.innerWidth
  canvas.height = window.innerHeight
  // 生成初始粒子,数量可按需调整
  particles = Array.from({ length: 150 }, () => new Particle())
  renderLoop()
}

// 渲染循环
const renderLoop = () => {
  ctx.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height)
  // 绘制鼠标渐变光晕
  const gradient = ctx.createRadialGradient(mouse.x, mouse.y, 0, mouse.x, mouse.y, mouse.radius)
  gradient.addColorStop(0, 'rgba(99, 102, 241, 0.15)')
  gradient.addColorStop(1, 'rgba(99, 102, 241, 0)')
  ctx.fillStyle = gradient
  ctx.fillRect(0, 0, canvasRef.value.width, canvasRef.value.height)
  // 更新绘制所有粒子
  particles.forEach(p => {
    p.update()
    p.draw()
  })
  animationId = requestAnimationFrame(renderLoop)
}

// 事件监听
const handleMouseMove = (e) => {
  mouse.x = e.clientX
  mouse.y = e.clientY
}
const handleResize = () => {
  canvasRef.value.width = window.innerWidth
  canvasRef.value.height = window.innerHeight
}

onMounted(() => {
  initCanvas()
  window.addEventListener('mousemove', handleMouseMove)
  window.addEventListener('resize', handleResize)
})

onUnmounted(() => {
  window.removeEventListener('mousemove', handleMouseMove)
  window.removeEventListener('resize', handleResize)
  cancelAnimationFrame(animationId)
})
</script>

<style scoped>
.canvas-wrapper {
  position: relative;
  width: 100vw;
  min-height: 100vh;
  background: #0f172a;
  overflow: hidden;
}
#mouse-effect {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
}
.page-content {
  position: relative;
  z-index: 1;
  color: #fff;
}
</style>

注意事项

  • 如果是Vue2项目,把上述Composition API的写法替换为Options API即可,核心动效逻辑完全通用
  • 可自行调整粒子数量、颜色、光晕半径、移动速度等参数,匹配你站点的设计风格
  • 移动端可以降低粒子数量避免性能损耗

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 10:06:05