# gif-tools **Repository Path**: hanxiaoxin/gif-tools ## Basic Information - **Project Name**: gif-tools - **Description**: react gif player & gif解码工具 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-10 - **Last Updated**: 2026-06-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: Web, React, Gif ## README # @libshub/gif-tools 基于 Canvas 的 React GIF 播放组件,使用 [gifuct-js](https://github.com/matt-way/gifuct-js) 解码,支持播放控制、循环次数、资源缓存、Worker 解码与加载性能统计。 ## 演示 [![GifPlayer 演示](https://static.hanlinbo.cn/%E5%9B%BE%E7%89%87/github/gif-tools-demo.png)](http://www.hanxiaoxin.cn/gif-tools/) 在线体验:[http://www.hanxiaoxin.cn/gif-tools/](http://www.hanxiaoxin.cn/gif-tools/) ## 安装 ```bash npm install @libshub/gif-tools ``` 需要 React 17+: ```bash npm install react react-dom ``` ## 快速开始 ```tsx import { GifPlayer } from '@libshub/gif-tools' import '@libshub/gif-tools/style.css' function App() { return ( ) } ``` ## GifPlayer ### Props | 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `src` | `string` | — | GIF 地址(必填) | | `width` | `number \| string` | — | 画布宽度 | | `height` | `number \| string` | — | 画布高度 | | `className` | `string` | — | 根节点 class | | `style` | `CSSProperties` | — | 根节点样式 | | `autoPlay` | `boolean` | `true` | 加载完成后自动播放 | | `showControls` | `boolean` | `false` | 显示播放/暂停按钮 | | `debug` | `boolean` | `false` | 在画面上叠加加载耗时调试信息 | | `useWorker` | `boolean` | `false` | 在 Web Worker 中解码,减轻主线程压力 | | `workerConcurrency` | `number` | `min(hardwareConcurrency, 4)` | Worker 池并发数,范围 1–16,仅 `useWorker=true` 时生效 | | `loopCount` | `number` | — | 循环次数,不传则按 GIF 自身循环或无限循环 | | `onLoaded` | `(stats: GifLoadStats) => void` | — | 加载完成 | | `onPlay` | `() => void` | — | 开始播放 | | `onPause` | `() => void` | — | 暂停 | | `onEnd` | `() => void` | — | 达到循环上限后结束 | | `onError` | `(error: Error) => void` | — | 加载或解码失败 | ### Ref 方法 通过 `ref` 可命令式控制播放器: ```tsx import { useRef } from 'react' import { GifPlayer, type GifPlayerRef } from '@libshub/gif-tools' const ref = useRef(null) ref.current?.play() // 播放 ref.current?.pause() // 暂停 ref.current?.toggle() // 切换播放/暂停 ref.current?.reset() // 回到第一帧并暂停 ref.current?.reload() // 重新加载(跳过 pending 复用,强制 fresh) ref.current?.isPlaying() // 是否正在播放 ``` ### Worker 解码 多 GIF 并发加载时,可将 decode 放到 Worker 池,避免阻塞主线程: ```tsx ``` 也可在应用层全局设置 Worker 池大小: ```ts import { setWorkerPoolSize } from '@libshub/gif-tools' setWorkerPoolSize(8) // 1–16 setWorkerPoolSize() // 恢复默认 min(hardwareConcurrency, 4) ``` ### 完整示例 ```tsx import { useRef } from 'react' import { GifPlayer, type GifPlayerRef } from '@libshub/gif-tools' import '@libshub/gif-tools/style.css' export default function Demo() { const playerRef = useRef(null) return ( <> console.log(`loaded in ${stats.totalMs.toFixed(1)}ms`)} onPlay={() => console.log('play')} onPause={() => console.log('pause')} onEnd={() => console.log('end')} onError={(e) => console.error(e)} /> ) } ``` ## 资源缓存 相同 `src` 的 GIF 在全局共享解码结果(不论是否使用 Worker),多个 `GifPlayer` 实例不会重复 fetch / decode。 ```tsx import { clearGifResourceCache } from '@libshub/gif-tools' clearGifResourceCache() ``` ## 加载统计 `GifLoadStats` `onLoaded` 回调中的 `GifLoadStats` 可区分三种加载模式,并拆分 network / queue / decode 三阶段: | 字段 | 说明 | |------|------| | `networkTimeMs` | 网络或浏览器缓存读取耗时(Resource Timing) | | `queueWaitMs` | Worker 池排队,或 pending 跟随方等待进行中的加载 | | `decodeTimeMs` | 实际 decode 耗时 | | `totalMs` | 墙钟总耗时(该实例从开始加载到就绪) | | `fromCache` | 命中内存缓存 | | `fromPending` | 等待同一 `src` 的进行中加载 | | 模式 | 判断 | 典型字段 | |------|------|----------| | **fresh** | `!fromCache && !fromPending` | `networkTimeMs`、`queueWaitMs`、`decodeTimeMs` | | **pending** | `fromPending` | `queueWaitMs`(其余为 0) | | **cache** | `fromCache` | 均为 0 | ```tsx import type { GifLoadStats } from '@libshub/gif-tools' onLoaded={(stats: GifLoadStats) => { if (stats.fromCache) { console.log('cache hit') return } if (stats.fromPending) { console.log(`pending queue ${stats.queueWaitMs.toFixed(1)}ms`) return } console.log( `network ${stats.networkTimeMs.toFixed(1)}ms`, `queue ${stats.queueWaitMs.toFixed(1)}ms`, `decode ${stats.decodeTimeMs.toFixed(1)}ms`, ) console.log(`wall ${stats.totalMs.toFixed(1)}ms`) }} ``` > 并发场景下,各实例 `totalMs` 为各自墙钟时间;整批加载的总耗时应取最慢实例的 `totalMs`,而非简单累加。 ## 底层 API 不依赖 React 时,可直接在 Canvas 上创建控制器: ```ts import { createGifController } from '@libshub/gif-tools' const canvas = document.querySelector('canvas')! const { controller, stats } = await createGifController(canvas, src, { useWorker: true, workerConcurrency: 4, loopCount: 3, onPlay: () => {}, onPause: () => {}, onEnd: () => {}, }) controller.play() controller.pause() controller.reset() controller.isPlaying() controller.getCompletedLoops() controller.destroy() ``` ## 导出一览 **组件** - `GifPlayer` **类型** - `GifPlayerProps`、`GifPlayerRef`、`GifPlayerComponent` - `GifLoadStats`、`GifController`、`CreateGifOptions` **工具函数** - `createGifController` — 在 Canvas 上创建 GIF 控制器 - `clearGifResourceCache` — 清空 GIF 资源缓存 - `setWorkerPoolSize` — 设置全局 Worker 池并发数(1–16),不传参则恢复默认 `min(hardwareConcurrency, 4)`