爱心鼠标跟随特效

爱心鼠标跟随特效

从零实现一个流畅、美观的爱心鼠标跟随特效,涵盖原理分析、组件编写、样式设计和性能优化。

爱心鼠标跟随特效

特效原理

鼠标跟随特效的核心思路很简单:监听鼠标移动事件,在鼠标位置创建一个带动画的元素,动画结束后自动移除。

整个流程可以拆解为四个环节:

  1. 捕获鼠标位置 — 监听 mousemove 事件,拿到 clientXclientY
  2. 生成爱心元素 — 在对应坐标创建一个 <span>♥</span>,附加随机参数(大小、颜色、旋转角度)
  3. 播放动画 — CSS @keyframes 驱动爱心从小变大再缩小、同时上飘并渐隐
  4. 清理元素 — 动画结束后从 DOM 中移除,避免内存泄漏

文件结构

本次实现涉及以下文件:

text
app/
├── components/blog/
│   └── BlogHeartCursor.vue    ← 新建:爱心特效组件
├── app.vue                    ← 修改:注册组件
└── app.config.ts              ← 修改:添加配置项

第一步:创建组件

新建文件 app/components/blog/BlogHeartCursor.vue,这是整个特效的核心。

模板部分

模板只需要一个容器和一个循环渲染的爱心列表:

html
<template>
<ClientOnly>
	<div v-if="enabled" class="heart-cursor" aria-hidden="true">
		<TransitionGroup name="heart" @after-leave="onAfterLeave">
			<span
				v-for="heart in hearts"
				:key="heart.id"
				:data-id="heart.id"
				class="heart-item"
				:style="{
					left: `${heart.x}px`,
					top: `${heart.y}px`,
					fontSize: `${heart.size}px`,
					color: heart.color,
					transform: `rotate(${heart.rotation}deg)`,
				}"
			>♥</span>
		</TransitionGroup>
	</div>
</ClientOnly>
</template>

几个关键设计决策:

  • <ClientOnly> 包裹,因为 mousemove 是浏览器事件,SSR 环境不存在
  • aria-hidden="true",爱心是纯装饰,不应被屏幕阅读器读取
  • <TransitionGroup> 管理爱心的进入/离开动画,@after-leave 在动画结束后清理数据
  • 每个爱心通过 :style 动态设置位置、大小、颜色和旋转

脚本部分

逐段说明:

节流控制throttleMs = 50 表示每 50ms 最多生成一个爱心。鼠标移动事件触发频率极高(每秒可达数百次),不做节流会瞬间创建大量 DOM 元素,拖慢页面。

随机参数 — 每个爱心在鼠标位置基础上偏移 ±10px(避免完全重叠),大小 10-24px 随机,旋转 ±20° 随机,颜色从 7 种粉红色系中随机选取。

数量上限hearts.value.length > 20 时移除最早的爱心,防止数组无限增长。

passive: true — 告诉浏览器事件回调不会调用 preventDefault(),允许浏览器在滚动时并行处理鼠标事件,提升性能。

onAfterLeave — Vue 的 <TransitionGroup> 在离开动画结束后触发,此时从数组中移除对应爱心数据。

样式部分

动画分三个阶段:

阶段时间点效果
弹出0% → 30%从 0.3 倍放大到 1.1 倍,略微上移,完全不透明
飘散30% → 100%缩小到 0.6 倍,上飘 60px,透明度降为 0
结束100%forwards 保持最终状态,随后被 onAfterLeave 清理

几个关键属性:

  • pointer-events: none — 爱心不会拦截点击,不影响页面交互
  • will-change: transform, opacity — 提示浏览器这两个属性会变化,提前创建合成层
  • filter: drop-shadow(...) — 给爱心加一层柔和的粉色光晕,增加质感
  • overflow: hidden — 容器裁剪超出视窗的爱心,避免出现滚动条

第二步:注册组件

打开 app/app.vue,在 <BlogPetals /> 下方添加一行:

html
<!-- 文件:app/app.vue -->
<!-- 在 <BlogPetals /> 后面添加 -->
<BlogHeartCursor />

Nuxt 3 的自动导入机制会识别 app/components/blog/BlogHeartCursor.vue,无需手动 import。

第三步:添加配置项

打开 app/app.config.ts,在 petals 配置后面添加:

ts
// 文件:app/app.config.ts
// 在 petals 配置项后面添加

heartCursor: {
	enabled: true,
},

这样可以通过 useAppConfig().heartCursor.enabled 在运行时控制特效开关,设为 false 即可关闭。

性能优化要点

优化手段说明
50ms 节流鼠标移动每秒最多触发 20 次,而非数百次
数组上限 20最多同时存在 20 个爱心 DOM 元素
will-change让浏览器为 transform 和 opacity 创建独立合成层,动画走 GPU
passive: true不阻塞浏览器的滚动优化
pointer-events: none爱心不参与命中测试,减少事件分发开销
onAfterLeave 清理动画结束后及时移除数据和 DOM

触屏适配

组件同时监听了 touchmove 事件,在手机上滑动时也会产生爱心。touch.clientX/Ymouse.clientX/Y 的坐标系一致,不需要额外转换。

自定义扩展

如果想调整特效风格,可以修改以下参数:

ts
// 爱心颜色,改成你喜欢的色系
const colors = [
	'rgba(100, 200, 255, 0.85)',  // 天蓝
	'rgba(150, 255, 200, 0.85)',  // 薄荷绿
]

// 生成频率,越小越密集(单位 ms)
const throttleMs = 30

// 爱心大小范围(单位 px)
size: 14 + Math.random() * 18,

// 上飘距离(CSS 动画中的 translateY)
translateY(-80px)

如果想把爱心换成其他符号(比如星星 ✦、樱花 ❀),只需修改模板中的 字符即可。

2026 御网杯 CTF Writeup 合集
努力学习逆向第一天

评论区

评论加载中...