使用Framer Motion实现径向渐变动画:解决鼠标离开跳变问题
文本聚光灯组件平滑过渡问题
我开发了一个给段落文本添加聚光灯效果的组件,采用radial-gradient作为背景图,结合background-clip: text实现效果。为让聚光灯跟随光标移动,我编写了handleMouseMove函数来设置useMotionValue,并用这些值调整渐变的X、Y位置。目前功能基本可用,但动画流畅性存在问题:当光标移出组件时,聚光灯应平滑回到中间位置,但当前handleMouseLeave仅能实现瞬间跳转,无法完成平滑过渡。
组件效果展示
- 默认状态(已修改颜色):

- 光标悬停在文本右端时,渐变中心移至对应位置:

问题动图演示

当前代码实现
const GradientBackgroundParagraph = ({ text }) => { let mouseX = useMotionValue(50); let mouseY = useMotionValue(50); const handleMouseMove = ({ clientX, clientY, currentTarget }) => { const { left, top, width, height } = currentTarget.getBoundingClientRect(); mouseX.set(((clientX - left) / width) * 100); mouseY.set(((clientY - top) / height) * 100); }; const handleMouseLeave = () => { mouseX.set(50); mouseY.set(50); }; return ( <motion.p onMouseMove={handleMouseMove} onMouseLeave={handleMouseLeave} style={{ backgroundImage: useMotionTemplate`radial-gradient(circle at ${mouseX}% ${mouseY}%, rgb(var(--foreground-rgb)), red)`, backgroundClip: "text", }} className="text-2xl bg-clip-text text-transparent cursor-default transition-all" > {text} </motion.p> ); };
解决方案
问题核心在于直接使用set方法修改motionValue,该方法是瞬间赋值,无过渡效果。要实现平滑过渡,需用Framer Motion的animate函数驱动motionValue变化,而非直接赋值。
修改后的代码如下:
import { motion, useMotionValue, useMotionTemplate, animate } from "framer-motion"; const GradientBackgroundParagraph = ({ text }) => { const mouseX = useMotionValue(50); const mouseY = useMotionValue(50); const handleMouseMove = ({ clientX, clientY, currentTarget }) => { const { left, top, width, height } = currentTarget.getBoundingClientRect(); // 鼠标移动时保持即时响应,若需平滑跟随可替换为animate mouseX.set(((clientX - left) / width) * 100); mouseY.set(((clientY - top) / height) * 100); }; const handleMouseLeave = () => { // 用animate实现平滑回归中间位置,可自定义时长和缓动曲线 animate(mouseX, 50, { duration: 0.5, ease: "easeOut" }); animate(mouseY, 50, { duration: 0.5, ease: "easeOut" }); }; return ( <motion.p onMouseMove={handleMouseMove} onMouseLeave={handleMouseLeave} style={{ backgroundImage: useMotionTemplate`radial-gradient(circle at ${mouseX}% ${mouseY}%, rgb(var(--foreground-rgb)), red)`, backgroundClip: "text", }} className="text-2xl bg-clip-text text-transparent cursor-default" > {text} </motion.p> ); };
关键修改说明
- 替换
handleMouseLeave中的set方法为animate函数,自动处理Motion值的平滑过渡 - 可通过
duration和ease参数调整过渡的快慢和动画曲线,适配不同场景需求 - 鼠标移动环节若需平滑跟随,也可将
set替换为animate,根据交互需求选择即可
内容的提问来源于stack exchange,提问作者Dantcho
相关产品推荐
相关产品推荐

