Deno Fresh Island中JavaScript动画无法触发的问题排查
问题分析与解决方案
你的代码存在的问题
onLoad事件在div上不生效:onLoad仅对<img>、<script>等媒体/外部资源类元素触发,普通<div>不会触发该事件,导致你的animation函数从未被调用。- 未遵循组件生命周期规范:Deno Fresh基于Preact,Island组件的初始化逻辑应通过
useEffect钩子执行,而非依赖元素事件。 - DOM元素获取方式不安全:直接使用
document.getElementById依赖DOM渲染顺序,且未严谨处理元素不存在的情况。 - 未清理定时器:组件卸载时若不清除
setInterval,会引发内存泄漏问题。
修正后的代码示例
import { useEffect, useRef } from "preact/hooks"; export default function StartAnimation() { const targetRef = useRef(null); const intervalRef = useRef(null); useEffect(() => { const target = targetRef.current; if (!target) return; let degree = 1; function frame() { target.style.transform = `rotate(${degree}deg)`; degree = degree === 360 ? 0 : degree + 1; } intervalRef.current = setInterval(frame, 10); // 组件卸载时清理定时器 return () => { if (intervalRef.current) { clearInterval(intervalRef.current); } }; }, []); return ( <div id="frame"> <div ref={targetRef}>Test animation</div> </div> ); }
Deno Fresh中添加动画的标准方式
方式一:JS钩子驱动动画(适合复杂交互场景)
- 用Preact的
useEffect处理组件挂载/更新时的动画初始化,useRef获取目标元素(避免重复查询DOM)。 - 必须在
useEffect的清理函数中清除定时器或取消动画帧,防止内存泄漏。 - 复杂动画建议用
requestAnimationFrame替代setInterval,可与浏览器刷新帧率同步,获得更流畅的效果。
方式二:CSS动画(适合简单、高性能需求)
对于旋转这类基础动画,CSS动画更高效,无需JS参与:
/* 在Island关联的CSS文件中定义 */ @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .rotating-element { animation: rotate 2s linear infinite; }
在组件中直接应用类名即可:
export default function StartAnimation() { return ( <div id="frame"> <div className="rotating-element">Test animation</div> </div> ); }
这种方式性能更优,浏览器会自动做硬件加速优化,代码也更简洁。
方式三:集成动画库(适合复杂动画场景)
如果需要复杂动画效果,可以引入framer-motion等专业动画库,Fresh的Island支持直接使用第三方npm包,只需在import_map.json中配置依赖即可。
内容的提问来源于stack exchange,提问作者Andrew Garrison
相关产品推荐
相关产品推荐

