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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 08:46:30