尧图精选

Motion Canvas 视频组件 `playbackRate` 为何不支持响应式(Reactive)以及正确的设置方式

🕒 发布时间:2026/9/20 20:54:52 📁 来源:尧图网络
Motion Canvas 视频组件playbackRate为何不支持响应式Reactive以及正确的设置方式【免费下载链接】motion-canvasVisualize Your Ideas With Code项目地址: https://gitcode.com/gh_mirrors/mo/motion-canvasMotion Canvas 的Video组件允许你像操作其他节点一样播放、暂停、缩放视频但它的playbackRate播放速率属性与src、alpha等属性不同——不能传入响应式值信号或函数。本指南将结合该警告文档与motion-canvas/2d的源码实现说明这条限制的由来、触发警告时的正确写法以及如果你想实现动态变速应当怎么做。背景Video组件与playbackRate属性在 Motion Canvas 中视频的使用方式与图片类似先导入视频文件再把它放入场景import {makeScene2D, Video} from motion-canvas/2d; import exampleMp4 from ../../videos/example.mp4; export default makeScene2D(function* (view) { view.add(Video src{exampleMp4} /); });不过这样只会显示视频、不会播放。要真正播放需要借助createRef创建引用然后调用play()/pause()详见 media.mdximport {createRef} from motion-canvas/core; export default makeScene2D(function* (view) { const videoRef createRefVideo(); view.add(Video ref{videoRef} src{exampleMp4} /); videoRef().play(); yield* videoRef().scale(1.25, 1.5).to(1, 1.5); });playbackRate是Video上的一个信号属性表示视频以正常速度的多少倍播放默认值为1/** * The rate at which the video plays, as multiples of the normal speed. * * defaultValue 1 */ initial(1) signal() public declare readonly playbackRate: SimpleSignalnumber, this;对应源码见 packages/2d/src/lib/components/Video.ts。该属性自 Motion Canvas 3.12.0 起随Video组件增强一并引入见 packages/2d/CHANGELOG.md 与 版本发布说明。警告内容playbackRate不能是响应式的仓库中的警告文档 reactive-playback-rate.md 明确说明TheplaybackRateof aVideocannot be reactive.也就是说Video的playbackRate不接受响应式值必须使用具体的数值number。当你向它传入函数包括信号本身时Motion Canvas 会通过 logger 输出一条警告提示你改用常量或先解包信号。错误写法传入函数// 错误不能传入函数 video.playbackRate(() 7);正确写法传入具体数值// 正确传入常量 video.playbackRate(7);如果你在用一个信号先取出它的值如果你确实希望从一个信号中读取速率请在赋值前调用信号取出当前值// 错误直接把信号传进去 video.playbackRate(mySignal);// 正确先调用信号取出具体数值 video.playbackRate(mySignal());注意这里传入的是当前时刻的值它不会随mySignal后续变化而自动更新——这与下文的实现原理直接相关。为什么playbackRate不能响应式源码级原理这条限制并非设计疏忽而是由Video的播放机制决定的。我们看 Video.ts 的几个关键实现。1.play()在开始时一次性烘焙速率Video.play()的实现如下Video.tspublic play() { const time useThread().time; const start time(); const offset this.time(); const playbackRate this.playbackRate(); this.playing(true); this.time(() this.clampTime(offset (time() - start) * playbackRate)); }可以看到play()在调用瞬间只读取一次this.playbackRate()然后把它作为常量参与后续的时间推进计算当前播放时间 clamp(起始偏移 (线程时间 - 开始时间) × 播放速率)也就是说播放速率被烘焙进了这个线性时间表达式。若允许传入响应式函数每次求值都会重新读取但底层 HTML 视频元素与时间计算却无法随之联动语义会变得混乱且不可预期——这正是它被设计为只接受具体数值的根本原因。2. 底层HTMLVideoElement由常量速率驱动Video内部通过一个静态池复用HTMLVideoElementVideo.ts并在绘制前把playbackRate写到原生元素上computed() protected seekedVideo(): HTMLVideoElement { const video this.video(); const time this.clampTime(this.time()); video.playbackRate this.playbackRate(); // 原生元素只接受一个具体数字 ... }fastSeekedVideo()中同样如此Video.ts。HTMLVideoElement.playbackRate本身就是标量属性传入函数没有任何意义这也从底层印证了必须传具体数值的要求。3.setPlaybackRate的兜底检查与警告在VideoProps中playbackRate的类型被刻意声明为number而非SignalValuenumberVideo.ts。但运行时仍可能通过方法调用传入函数因此setPlaybackRate做了兜底校验Video.tsprotected setPlaybackRate(playbackRate: number) { let value: number; if (isReactive(playbackRate)) { value playbackRate(); useLogger().warn({ message: Invalid value set as the playback rate, remarks: reactivePlaybackRate, inspect: this.key, stack: new Error().stack, }); } else { value playbackRate; } this.playbackRate.context.setter(value); ... }流程是用isReactive判断传入值是否为函数typeof value function见 packages/core/src/signals/utils.ts若是函数立即调用一次取出数值同时通过useLogger().warn发出警告警告的remarks正是 reactive-playback-rate.md 这份文档的内容它会以可读文本形式呈现给用户。4. 警告文档如何进入运行时reactive-playback-rate.md在 Video.ts 中以import reactivePlaybackRate from ./__logs__/reactive-playback-rate.md;的方式导入。仓库的 TypeScript 转换器 markdown-literals.js 会把这类*.md导入编译为渲染后的 HTML 字符串供 logger 在警告消息中展示。这是 Motion Canvas 日志即文档 的做法把详细的说明性文案放在 markdown 中随源码一起维护。实践中如何正确设置与变相实现动态速率综合以上原理可以总结出几条实践准则常量倍速这是最常见的用法直接赋数字即可例如 2 倍速播放videoRef().playbackRate(2); videoRef().play();从信号取值若速率来自某个信号如用户配置或随机值先解包再赋值const speed createSignal(1.5); // 只在赋值瞬间读取一次当前值 videoRef().playbackRate(speed());想在动画中改变播放速率怎么办由于playbackRate不支持响应式不能在动画过程中平滑跟随一个信号。但你可以分阶段设置在动画的不同时间点用videoRef().playbackRate(新值)直接切换为新的常量速率配合pause()/play()需要变速时先暂停、设置新速率、再播放setPlaybackRate内部在值为 0 时会自动暂停见 Video.ts改用seek(time)如果只想跳到某个时间点展示使用seek()Video.ts比依赖速率更可控。另外注意playbackRate为0时会被视为暂停Video.ts因此不要期望用0实现冻结画面后还能从信号恢复。小结Video.playbackRate只接受具体数值不接受函数或信号否则会触发 logger 警告原因在于play()启动时只读取一次速率并烘焙进时间推进计算底层HTMLVideoElement.playbackRate也是标量属性二者都不支持响应式语义正确做法是传常量或先用mySignal()取出信号当前值再赋值需要在动画中变速时请分阶段设置新速率或配合pause()/play()/seek()实现可控播放。【免费下载链接】motion-canvasVisualize Your Ideas With Code项目地址: https://gitcode.com/gh_mirrors/mo/motion-canvas创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →