尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

react-keyframes源码深度解析:89行TypeScript如何实现React逐帧动画?

react-keyframes源码深度解析:89行TypeScript如何实现React逐帧动画? react-keyframes源码深度解析89行TypeScript如何实现React逐帧动画【免费下载链接】react-keyframesCreate frame-based animations in React项目地址: https://gitcode.com/gh_mirrors/re/react-keyframesreact-keyframes 是一个在 React 中创建**逐帧动画frame-based animations**的轻量开源组件库。它的核心源码只有 89 行 TypeScript却实现了像翻动画胶片一样的帧切换效果——每个 Frame 子元素按设定时长依次显示非常适合打字机效果、轮播文案、步骤动画等场景。本文带你逐段读懂这 89 行代码背后的设计思路。什么是逐帧动画react-keyframes 解决什么问题传统 CSS 动画关注过渡而逐帧动画关注离散画面你把每一帧的画面写成独立的 React 元素组件按顺序、按时长一帧一帧地切换它们视觉上就像 Gif 一样在放映用 react-keyframes实现方式简单到只需两个组件import { Keyframes, Frame } from react-keyframes; function MyComponent() { return ( Keyframes Frame duration{500}This/Frame Frame duration{500}This is/Frame Frame duration{500}This is emanimated/em./Frame /Keyframes ); }效果每 500 毫秒切换一帧依次显示 This → This is → This is animated.。快速上手安装 react-keyframes 并获取源码npm install --save react-keyframes如果需要阅读或修改源码可克隆仓库git clone https://gitcode.com/gh_mirrors/re/react-keyframes打开仓库后全部核心逻辑都在这一个文件里packages/react-keyframes/src/index.ts仅 89 行。官方说明见readme.md。源码结构一览89 行里都有什么packages/react-keyframes/src/index.ts由三部分组成部分代码位置职责Frame函数组件第 14–24 行帧的容器壳本身几乎不做事Keyframes类组件第 26–89 行动画引擎管状态、管定时器、管渲染类型定义第 4–12 行Props / State 的 TypeScript 声明下面逐段拆解。核心组件一Frame 只是占位符export function Frame({ component, ...rest }) { return React.createElement(component, rest); }Frame看起来在渲染一个元素但实际上它永远不会被真正渲染——因为Keyframes从不渲染它的 children 列表而是通过children[i]直接取出每一帧的 React 元素对象。这里有个关键 TypeScript 技巧type Props { children: any; [frameProp: string]: any; // 允许任意 props比如 duration };duration{500}这类自定义属性通过索引签名被合法地接收下来存进frame.props中等待引擎读取。核心组件二Keyframes 动画引擎1. 状态极简只用一个 frameNumconstructor(props) { super(props); this.state { frameNum: 0 }; }整个动画系统只有一个状态当前帧号。初始为 0即显示第一帧。这是简单状态驱动的经典范例——复杂动画 简单状态 定时器。2. getFrame按帧号取画面getFrame() { return this.props.children[this.state.frameNum]; }children是 Frame 元素的数组frameNum就是下标。放映机的本质就是一句数组下标访问。3. render只渲染当前这一帧render() { const frame this.getFrame(); if (!frame) return null; const { component span, children, ...rest } this.props; return React.cloneElement(frame, { component, ...rest, ...frame.props }); }三个细节值得品味component默认spanKeyframes在页面上渲染成什么标签由它决定可以传div、pre甚至 React 组件...rest透传写在Keyframes classNamex上的其他属性会原样作用到渲染出来的元素上...frame.props合并当前帧上的属性优先级最高实现每帧可微调样式4. 定时器驱动帧推进requestNextFrame waitForDelayrequestNextFrame() { this.waitForDelay(() { const frameNum this.state.frameNum 1; if (this.props.children.length frameNum) return; // 播完停止 this.setState({ frameNum }); }); } waitForDelay(fn) { const currentFrame this.getFrame(); const delay currentFrame.props.duration || 0; // 未设 duration 默认 0ms clearTimeout(this.timer); this.timer setTimeout(fn, delay); }动画循环的节奏感完全由当前帧的duration决定定时器到期 →frameNum 1越界检查children.length frameNum→ 播完即停动画只播放一遍setState触发重新渲染 →componentDidUpdate再次调用requestNextFrame()→ 排定下一帧这就是一个自驱动的状态变更 → 生命周期钩子 → 下一轮定时器循环没有任何副作用库参与。5. 生命周期即启动 停止componentDidMount() { this.requestNextFrame(); } componentDidUpdate() { this.requestNextFrame(); } componentWillUnmount() { clearTimeout(this.timer); }挂载时启动第一帧的计时每次更新换帧后重新排定下一帧卸载时清理定时器避免内存泄漏和幽灵定时器——这是很多手写动画组件容易踩的坑6. shouldComponentUpdate一帧一帧的闸门shouldComponentUpdate(_nextProps, nextState) { const { frameNum } nextState; if (this.state.frameNum frameNum) return false; return frameNum 0 frameNum this.props.children.length; }它做了两件事帧号没变就跳过渲染防御性短路帧号越界就拒绝更新保证动画停在最后一帧而不是白屏单元测试用 Jest 假定时器验证帧切换测试文件test/index.test.tsx展示了如何可靠地测试基于时间的组件jest.useFakeTimers(); jest.advanceTimersByTime(100); // 手动推进 100ms断言已切到第 2 帧用jest.advanceTimersByTime替代真实等待测试既快又确定。项目测试配置极简jest.config.js只有一行preset: ts-jest让 Jest 直接跑 TypeScript。工程结构Lerna microbundle 的轻量发布链路lerna.jsonLerna monorepo 配置管理packages/*canary 与 master 分支均可发布packages/react-keyframes/package.json用microbundle构建--external react把 React 设为外部依赖产物同时输出 ESMdist/index.mjs与 CJSdist/index.js双格式覆盖打包器与 Node 环境publish-release.sh一键发布脚本这套小工具链保证了库体积极小、依赖干净。总结89 行代码的 4 个可复用设计思想 单一状态源动画进度只由frameNum一个数字表达一切由此派生props 即 APIduration、component通过普通属性传递用 TS 索引签名优雅承接生命周期驱动mount 启动、update 续帧、unmount 清理定时器节奏清晰无泄漏只渲染当前帧每帧独立成 React 元素cloneElement合并属性天然支持任意子内容当你需要打字机、逐句文案、分步演示这类离散画面动画时react-keyframes 这种逐帧方案比 CSS 过渡更直观——把每一帧写成 JSX剩下的交给这 89 行 TypeScript。【免费下载链接】react-keyframesCreate frame-based animations in React项目地址: https://gitcode.com/gh_mirrors/re/react-keyframes创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表