Deno Fresh应用Island加载缓慢及交互异常问题求助
Deno Fresh应用问题修复方案
问题1:无缓存环境下首次点击About按钮无响应
原因分析
- Navigation组件的
useEffect未设置依赖数组,导致组件每次渲染都会重复绑定/解绑scroll事件,引发状态不稳定,干扰导航链接的事件绑定。 - 若Links组件使用原生
<a>标签而非Fresh的客户端路由<Link>组件,首次加载时可能因组件未完成hydration,导致点击事件无法触发。
修复步骤
- 给Navigation的
useEffect添加空依赖数组,确保scroll事件只绑定一次:
useEffect(() => { const handleScroll = () => { const position = globalThis.window.scrollY; const threshold = 300; if (position > threshold && position < prevPosition.current) { isHidden.value = false; } else if (position > threshold) { isHidden.value = true; } else { isHidden.value = false; } prevPosition.current = position; }; self.window.addEventListener("scroll", handleScroll); return () => { self.window.removeEventListener("scroll", handleScroll); }; }, []); // 添加空依赖数组
- 确认Links组件使用Fresh官方的
<Link>组件:
import { Link } from "$fresh/runtime.ts"; // 替换原有<a>标签为<Link> <Link href="/about">About</Link>
问题2:安卓手机滚动到About区域时动画卡顿
原因分析
- Skills组件中使用大量嵌套
setTimeout频繁更新signal,触发组件多次重渲染,占用移动端有限的主线程资源。 - 基于
color属性的过渡动画会触发浏览器重绘,无法利用GPU加速,导致卡顿。 - IntersectionObserver回调在元素进入视口时一次性执行大量定时器任务,造成任务队列阻塞。
修复步骤
- 优化定时器逻辑,用
requestAnimationFrame替代setTimeout,减少主线程阻塞:
useEffect(() => { const observer = new IntersectionObserver((entries) => { if (entries[0].isIntersecting && !animationPlayed.value) { let step = 0; const totalSkills = skills.length; const animate = () => { if (step < totalSkills) { active.value = skills[step].name; step++; requestAnimationFrame(() => setTimeout(animate, 140)); } else { setTimeout(() => { active.value = null; setTimeout(() => { flashIcons.value = true; setTimeout(() => { flashIcons.value = false; active.value = skills[0].name; animationPlayed.value = true; }, 300); }, 300); }, 110); } }; animate(); observer.disconnect(); } }, { rootMargin: "0px 0px -50px 0px" }); // 提前50px触发动画,避免卡顿 const skillsElement = document.getElementById("skills"); if (skillsElement) observer.observe(skillsElement); return () => observer.disconnect(); }, []);
- 修改动画属性,利用GPU加速:
把图标颜色过渡替换为transform: scale配合颜色变化,添加will-change提示浏览器优化:
<Icon class={` cursor-pointer transition-all duration-300 ease-in-out will-change:transform,color hover:scale-110 hover:text-blue-600 dark:hover:text-neutral-300 ${active.value === name ? "scale-110 text-blue-600 dark:text-neutral-300" : ""} `} onClick={() => (active.value = name)} />
- 用CSS关键帧动画替代JS控制的闪烁效果:
在全局样式中添加:
@keyframes iconFlash { 0% { color: theme('colors.neutral.600'); } 50% { color: theme('colors.blue.600'); } 100% { color: theme('colors.neutral.600'); } } .dark @keyframes iconFlash { 0% { color: theme('colors.neutral.600'); } 50% { color: theme('colors.neutral.300'); } 100% { color: theme('colors.neutral.600'); } } .flash-icons { animation: iconFlash 0.6s ease-in-out; }
然后修改Skills组件的section:
<section id="skills" class={` grid place-items-center gap-y-8 text-neutral-600 ${flashIcons.value ? "flash-icons" : ""} `} >
内容的提问来源于stack exchange,提问作者Mac
相关产品推荐
相关产品推荐

