鼠标星星跟随特效:用 jQuery 与原生 JS 打造轻量级粒子拖尾
发布时间:2026/9/26 13:43:32来源:尧图网络
1. 鼠标星星跟随特效到底能做什么适合谁用鼠标星星跟随特效指的是鼠标在页面上移动时光标轨迹上不断冒出星星、光点或粒子并带着拖尾慢慢消散的视觉效果。它本质上是一个轻量级的 Canvas 或 DOM 粒子系统监听mousemove拿到坐标在坐标处生成一个粒子对象每帧更新它的位置、透明度和缩放生命周期结束后销毁。听起来有点抽象你可以把它理解成「鼠标走过的地方撒了一把会自己消失的荧光粉」。这类特效最适合三类场景。第一是个人主页、简历页、作品集访客停留时间短一个不抢内容的动态点缀能明显提升「这页有点东西」的第一印象。第二是活动页、节日专题页、抽奖落地页星星拖尾能配合主题色营造氛围成本却几乎为零。第三是产品官网的首屏作为背景层的装饰粒子不干扰按钮点击和文案阅读。它不适合谁不适合后台管理系统、数据看板、长文阅读页。原因很直接粒子持续创建和销毁会占用主线程在低端安卓机上可能把滚动帧率从 60 拉到 40 以下而且满屏乱飞的星星会分散注意力对需要专注阅读或操作的界面是负优化。所以判断标准很简单页面以「展示和氛围」为主就上页面以「阅读和操作」为主就别上。下面我会先讲清楚接入前要准备什么再分别给出 jQuery 版和原生 JS 版的可复制代码最后给出帧率与移动端的验证步骤以及我实际踩过的几个坑。2. 接入前的准备TaoToken 能帮你做什么写这类特效最烦的不是算法而是调试过程中的两个环节一是想快速验证某段粒子逻辑对不对二是想让 AI 帮你把 jQuery 写法翻译成原生 JS 写法或者反过来。这两个环节都需要一个稳定的模型调用入口。TaoToken 在这里的角色是「统一的模型 API 网关」。你不需要在本地装一堆 SDK也不用为每个模型单独申请一套凭证注册后在控制台创建一个 API Key就能用同一套 OpenAI 兼容协议去调用不同模型。对前端开发者来说这意味着你可以把「帮我优化这段粒子代码的性能」这类问题直接通过一个 HTTP 请求丢给模型拿到改写建议后再贴回编辑器。具体入口我列一下按需取用想先聊两句、验证模型回答质量模型对话入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodel_chat想长期用 AI 辅助写前端、做 AgentCoding Plan 入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcoding_plan想管理额度和查看用量控制台入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentconsole想创建和复制 API KeyAPI Keys 入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi_keys想看接口参数和调用示例接入文档入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdocAPI 的基础地址是https://taotoken.net/api注意这个地址不带任何查询参数直接作为base_url使用即可。如果你用的是 Claude Code 这类工具Anthropic 兼容入口在https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentclaude_code。注意API Key 只创建一次就够复制后存在本地环境变量里不要写进前端代码提交到仓库。前端页面里出现的任何 Key 都等于公开。3. 可复制配置jQuery 版与原生 JS 版粒子拖尾这一节是全文的核心两套代码都能直接跑。我建议你先用原生 JS 版因为它没有外部依赖加载更快jQuery 版适合你的项目本来就已经引入了 jQuery 的情况避免为了一个特效再引一个库。3.1 原生 JS 版零依赖直接复制新建一个star-trail.js内容如下。核心思路是用一个固定定位的容器承载所有粒子每个粒子是一个span用transform: translate3d做位移以触发 GPU 合成用scale配合lifeSpan做淡出缩小。(function () { // 只在非触屏设备启用避免移动端误触和性能浪费 var isTouch ontouchstart in window || navigator.msMaxTouchPoints; if (isTouch) return; var COLORS [#D61C59, #E7D84B, #1B8798, #F73859, #14FFEC, #00E0FF, #FF99FE, #FAF15D]; var MAX_PARTICLES 120; // 粒子上限防止快速移动时爆量 var LIFE 120; // 生命周期单位帧 var container document.createElement(div); container.className js-cursor-container; container.style.cssText position:fixed;inset:0;pointer-events:none;z-index:9999;overflow:hidden;; document.body.appendChild(container); var particles []; var cursor { x: window.innerWidth / 2, y: window.innerHeight / 2 }; function addParticle(x, y) { if (particles.length MAX_PARTICLES) return; var el document.createElement(span); el.textContent *; el.style.cssText position:fixed;top:0;left:0;pointer-events:none;will-change:transform; font-size:25px;line-height:1;color: COLORS[(Math.random() * COLORS.length) | 0] ;; container.appendChild(el); particles.push({ el: el, x: x 10, y: y 10, vx: (Math.random() 0.5 ? -1 : 1) * (Math.random() / 2), vy: 1, life: LIFE }); } function update() { for (var i particles.length - 1; i 0; i--) { var p particles[i]; p.x p.vx; p.y p.vy; p.life--; if (p.life 0) { p.el.remove(); particles.splice(i, 1); continue; } var scale p.life / LIFE; p.el.style.transform translate3d( p.x px, p.y px,0) scale( scale ); p.el.style.opacity scale; } requestAnimationFrame(update); } document.addEventListener(mousemove, function (e) { cursor.x e.clientX; cursor.y e.clientY; addParticle(cursor.x, cursor.y); }); requestAnimationFrame(update); })();在 HTML 里引入即可放在/body前script src./star-trail.js/script3.2 jQuery 版适合已有 jQuery 的项目如果你的页面已经加载了 jQuery可以省掉原生 DOM 操作的样板代码写起来更短。注意这里用的是$(span)创建元素事件绑定用$(document).on(mousemove)。(function ($) { if (!$) return; var isTouch ontouchstart in window || navigator.msMaxTouchPoints; if (isTouch) return; var COLORS [#D61C59, #E7D84B, #1B8798, #F73859, #14FFEC, #00E0FF, #FF99FE, #FAF15D]; var MAX_PARTICLES 120; var LIFE 120; var $container $(div classjs-cursor-container/div).css({ position: fixed, inset: 0, pointerEvents: none, zIndex: 9999, overflow: hidden }).appendTo(body); var particles []; function addParticle(x, y) { if (particles.length MAX_PARTICLES) return; var $el $(span*/span).css({ position: fixed, top: 0, left: 0, pointerEvents: none, willChange: transform, fontSize: 25px, lineHeight: 1, color: COLORS[Math.floor(Math.random() * COLORS.length)] }).appendTo($container); particles.push({ $el: $el, x: x 10, y: y 10, vx: (Math.random() 0.5 ? -1 : 1) * (Math.random() / 2), vy: 1, life: LIFE }); } function update() { for (var i particles.length - 1; i 0; i--) { var p particles[i]; p.x p.vx; p.y p.vy; p.life--; if (p.life 0) { p.$el.remove(); particles.splice(i, 1); continue; } var scale p.life / LIFE; p.$el.css({ transform: translate3d( p.x px, p.y px,0) scale( scale ), opacity: scale }); } requestAnimationFrame(update); } $(document).on(mousemove, function (e) { addParticle(e.clientX, e.clientY); }); requestAnimationFrame(update); })(window.jQuery);引入方式script srchttps://cdn.jsdelivr.net/npm/jquery3.7.1/dist/jquery.min.js/script script src./star-trail-jq.js/script3.3 两版关键参数对照参数作用建议值调大后果调小后果MAX_PARTICLES同屏粒子上限80–150快速移动时卡顿拖尾稀疏不连贯LIFE粒子存活帧数90–150拖尾过长、堆积星星一闪即逝fontSize星星大小18–28px遮挡内容几乎看不见vy下落速度0.5–1.5掉得太快像下雨悬浮不动vx随机范围左右飘散幅度±0.5散得太开不成线轨迹太直提示MAX_PARTICLES是最重要的性能阀门。鼠标快速划过屏幕时mousemove每秒能触发上百次如果不设上限粒子数会瞬间破千帧率直接崩。加上限后超出部分直接丢弃视觉上几乎看不出差别。4. 验证请求与成功结果怎么确认特效真的生效代码贴进去不等于生效我按「先看现象、再看数据」的顺序给你一套验证流程。第一步打开页面把鼠标从左上角缓慢划到右下角。正常情况下你会看到一条由彩色星号组成的拖尾星星一边下落一边缩小变淡大约 2 秒后完全消失。如果星星出现但不动说明requestAnimationFrame的循环没跑起来检查update函数是否在最后被调用。第二步打开 Chrome DevTools 的 Performance 面板点录制然后在页面上快速画圈 5 秒停止录制。看 FPS 曲线稳定在 55–60 之间算合格。如果出现大量红条或掉到 30 以下先把MAX_PARTICLES降到 60 再测一次。第三步验证移动端。用 DevTools 的设备模拟切到 iPhone SE刷新页面。因为代码里有isTouch判断触屏设备应该完全不生成粒子这是预期行为。如果你确实想在移动端也开把if (isTouch) return;这行注释掉但要做好掉帧的心理准备。第四步验证不干扰交互。在特效开启的状态下点击页面上的按钮、链接、输入框确认都能正常响应。因为容器设了pointer-events: none理论上不会拦截事件但如果你自己改过样式要重新确认这一条。如果你在调试过程中想让 AI 帮你分析 Performance 录制的数据或者把这段代码改成 Canvas 版本可以把代码贴到模型对话入口里问比在搜索引擎里翻半天快得多。5. 本篇常见错误排查这一节是我实际踩过的坑按出现频率排序。错误一星星全部堆在左上角不动。原因是transform没生效粒子元素的初始位置是top:0;left:0如果translate3d写错或没执行所有星星就叠在原点。检查p.el.style.transform这行有没有被正确赋值以及p.x、p.y是否在累加。错误二页面出现横向滚动条。粒子飘到屏幕右侧外时如果容器没有overflow: hidden会把页面撑宽。原生版里我在容器上加了overflow:hiddenjQuery 版也有确认这两处没被删掉。错误三移动端一碰就满屏星星还卡死。说明isTouch判断失效或者你手动注释掉了。移动端的touchmove触发频率和坐标体系与鼠标不同直接复用mousemove逻辑会出问题。要么保持禁用要么单独监听touchmove并做节流。错误四星星挡住了导航栏或弹窗。容器的z-index: 9999太高。把它降到比你的导航低、比背景高的层级比如z-index: 10具体值看你的页面结构。错误五jQuery 版报$ is not defined。说明 jQuery 还没加载完你的特效脚本就执行了。把特效脚本放在 jQuery 的script之后或者用$(function(){ ... })包一层。错误六快速移动时星星断成一段一段的。这是mousemove采样间隔导致的鼠标移动太快时两次事件之间的坐标跨度大粒子之间就有了空隙。解决办法是在两次坐标之间做线性插值补几个中间粒子。这个优化可以让 AI 帮你写把「在 mousemove 的上一坐标和当前坐标之间插值生成粒子」这个需求描述清楚即可。注意所有排查都建议在 DevTools 的 Console 里先看有没有报错。90% 的「特效不生效」其实是某一行 JS 抛了异常后面的代码全没执行。6. 下一步把特效接进你的项目代码能跑之后接下来是工程化的问题。如果你只是给一个静态页面加点缀直接把star-trail.js引入就行。如果是 Vue、React 项目建议把它封装成一个组件或自定义 Hook在mounted或useEffect里初始化在卸载时移除事件监听和容器避免内存泄漏。想长期用 AI 辅助这类前端特效开发比如让它帮你把 DOM 版改写成 Canvas 版、加个鼠标按下时粒子爆发的效果、或者做一套可配置的参数面板可以走 Coding Plan 入口把重复的代码改写和调试交给模型你专注在视觉调优上。需要先拿 Key 的话API Keys 入口创建后复制到本地环境变量接口地址用https://taotoken.net/api具体参数看接入文档。最后留一个实用技巧把COLORS数组换成你项目的主题色把*换成✦或·整个特效的气质会完全不同。星星不一定非得是星号一个圆点、一个爱心、甚至一个品牌 logo 的字符都能成为页面的记忆点。
网站建设高端定制企业官网