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

如何用Framer Motion实现Framer风格Ticker?循环异常求助

Framer Motion Ticker组件循环功能失效问题排查与修复

问题描述

尝试用Framer Motion实现类似Framer官方Ticker的滚动效果,但循环功能无法正常运行,当前代码及属性配置参考图如下:

当前代码

<AnimatePresence>
  <ul className='AnimationLine'>
    {
      data.map((item) => (
        <motion.li
          key={item.id}
          initial={{
            y: "100%",
            opacity: 0
          }}
          animate={{
            y: "-100%",
            opacity: 1
          }}
          exit={{
            y: "-100%",
            opacity: 0
          }}
          transition={{
            duration: 0.5,
            loop: Infinity,
            type: "ticker",
            speed: 1,
            // direction: "bottom",
            align: "center",
            gap: 10,
            padding: 10
          }}
          whileHover={{
            scale: isHovered
              ? 1.2
              : 0.5
          }}
          onHoverStart={() => setIsHovered(true)}
          onHoverEnd={() => setIsHovered(false)}>
          {item.name}
        </motion.li>
      ))
    }
  </ul>
</AnimatePresence>

属性参考图

Framer Ticker属性参考图


问题根源

  1. 属性配置错误:Framer官方Ticker的type: "ticker"、gap、padding等是组件专属props,并非motion元素的transition参数,直接放到transition里不会生效。
  2. 动画逻辑错误:给单个<motion.li>设置loop: Infinity,只会让每个列表项重复自身的上下位移,无法实现整个列表的滚动循环。
  3. 冗余组件干扰:AnimatePresence用于处理组件挂载/卸载动画,与Ticker滚动逻辑无关,反而可能引发冲突。
  4. hover状态冗余:whileHover可以直接定义动画,无需额外维护isHovered状态。

修复方案

方案1:使用Framer官方Ticker组件

直接使用封装好的Ticker组件,配置对应props即可实现循环滚动:

import { Ticker } from "framer-motion";

// 组件内使用
<Ticker
  direction="bottom"
  speed={1}
  align="center"
  gap={10}
  padding={10}
>
  {data.map((item) => (
    <motion.li
      key={item.id}
      whileHover={{ scale: 1.2 }} // 直接用whileHover,无需额外状态
    >
      {item.name}
    </motion.li>
  ))}
</Ticker>

方案2:自定义实现循环滚动

如果不想依赖官方Ticker组件,可通过复制列表内容+匀速滚动动画实现无缝循环:

import { motion } from "framer-motion";

const CustomTicker = ({ data }) => {
  return (
    <div className="ticker-container" style={{ overflow: "hidden", height: "fit-content" }}>
      {/* 复制一份列表,实现无缝衔接 */}
      <motion.div
        className="ticker-content"
        animate={{ y: "-100%" }} // 纵向滚动,横向改为x: "-50%"
        transition={{
          duration: 10, // 滚动时长,根据需求调整
          repeat: Infinity,
          ease: "linear" // 匀速滚动,保证流畅性
        }}
        style={{ display: "flex", flexDirection: "column" }} // 纵向布局,横向改为row+whiteSpace: nowrap
      >
        {[...data, ...data].map((item, idx) => (
          <motion.li
            key={`${item.id}-${idx}`}
            style={{ margin: "10px 0" }} // 对应gap属性
            whileHover={{ scale: 1.2 }}
          >
            {item.name}
          </motion.li>
        ))}
      </motion.div>
    </div>
  );
};

注意事项

  • 方案1需确保安装了正确版本的@framer/motion,部分版本可能需单独引入Ticker组件。
  • 自定义实现时,必须复制列表内容,否则滚动到末尾会出现空白。
  • 移除冗余的AnimatePresence和isHovered状态,简化代码逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 09:10:37