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

React中根据localStorage存储的主题设置Lottie动画初始帧的实现问题

React中根据localStorage存储的主题设置Lottie动画初始帧的实现问题

嘿,我之前做暗黑模式切换组件的时候,刚好也用了Lottie动画,碰到了和你一模一样的问题——手动点击切换过渡帧没问题,但页面刚加载时,动画初始状态总跟localStorage里存的主题对不上。给你分享下我是怎么搞定的,应该能直接套用!

首先,咱们得先搞定初始主题的获取:页面加载时,先从localStorage里读之前存的主题,如果没有的话,就用系统的深色模式偏好,或者默认设为浅色模式,这个看你需求。

然后核心是控制Lottie的初始帧——咱们需要拿到Lottie的实例,这样才能调用它的setCurrentFrame方法,在组件刚挂载时就把帧跳到对应主题的状态。

我给你贴个完整的组件代码示例,你可以根据自己的动画帧号调整:

import { useRef, useState, useEffect } from 'react';
import Lottie from 'react-lottie';
import themeSwitchAnim from './theme-switch.json'; // 替换成你的Lottie动画文件

const ThemeToggleBtn = () => {
  // 第一步:获取初始主题
  const getSavedTheme = () => {
    const saved = localStorage.getItem('app-theme');
    // 有存储就用存储的,没有就看系统偏好,默认浅色
    if (saved) return saved;
    return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
  };

  const [currentTheme, setCurrentTheme] = useState(getSavedTheme);
  const lottieInstanceRef = useRef(null); // 存Lottie实例用的ref

  // 第二步:初始化/切换主题时设置对应帧
  useEffect(() => {
    if (!lottieInstanceRef.current) return;

    // 这里要注意!替换成你的动画实际对应的帧号
    // 比如我的动画里,浅色状态对应帧0,深色状态对应帧30(根据你的动画调整)
    const targetFrame = currentTheme === 'dark' ? 30 : 0;
    lottieInstanceRef.current.setCurrentFrame(targetFrame);
  }, [currentTheme]);

  // 第三步:主题切换的点击事件
  const handleToggleTheme = () => {
    const newTheme = currentTheme === 'light' ? 'dark' : 'light';
    setCurrentTheme(newTheme);
    localStorage.setItem('app-theme', newTheme);

    // 控制Lottie播放对应的过渡动画
    if (lottieInstanceRef.current) {
      if (newTheme === 'dark') {
        // 播放从浅色到深色的片段,比如帧0到30
        lottieInstanceRef.current.playSegments([0, 30], true);
      } else {
        // 播放从深色到浅色的片段,比如帧30到0
        lottieInstanceRef.current.playSegments([30, 0], true);
      }
    }

    // 别忘了同步更新页面的主题样式(比如给html加dark类)
    document.documentElement.classList.toggle('dark', newTheme === 'dark');
  };

  // Lottie的基础配置,一定要关自动播放!
  const lottieOptions = {
    loop: false,
    autoplay: false,
    animationData: themeSwitchAnim,
    rendererSettings: {
      preserveAspectRatio: 'xMidYMid slice'
    }
  };

  return (
    <div onClick={handleToggleTheme} style={{ cursor: 'pointer', width: '48px' }}>
      <Lottie
        options={lottieOptions}
        ref={(ref) => {
          // 把Lottie实例存到ref里
          if (ref) lottieInstanceRef.current = ref;
        }}
        width="100%"
      />
    </div>
  );
};

export default ThemeToggleBtn;

这里有几个关键的点你要注意:

  • 帧号一定要对应你的动画:你得自己打开Lottie动画文件,确认浅色状态对应的是哪一帧,深色状态对应的是哪一帧,别直接抄我代码里的30,不然肯定不对!
  • 一定要关autoplay:如果开了自动播放,初始化时动画会自己跑,就覆盖咱们设置的初始帧了,这个坑我当初踩过!
  • 同步页面主题:切换主题时,别忘了给页面的根元素加/删dark类,不然只有动画变了,页面样式没跟上,就尴尬了。

如果你的项目里用的是原生lottie-web而不是react-lottie库,逻辑也是一样的——只要拿到Lottie的实例,调用setCurrentFrame和playSegments就行,只是初始化实例的方式会有点不同,比如用lottie.loadAnimation()来创建实例,然后存在ref里。

备注:内容来源于stack exchange,提问作者jacobadam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 16:38:04