document.querySelector 与 classList.toggle 是实现页面动态效果最轻量可靠的基础组合,应通过 CSS 类而非 style.display 控制显隐,用 requestAnimationFrame 替代 setTimeout 实现平滑动画,scroll/resize 需节流,且需根据环境判断动效必要性与降级策略。

document.querySelector 和 classList.toggle 是实现大多数页面动态效果最轻量、最可靠的基础组合。
点击切换元素显隐,别用 display: none 硬切
直接操作 style.display 会覆盖 CSS 中定义的其他显示逻辑(比如响应式断点里的 display: flex),也难维护。更稳妥的方式是通过 CSS 类控制:
button.addEventListener('click', () => {
const panel = document.querySelector('#sidebar');
panel.classList.toggle('is-hidden');
});对应 CSS 写成:
.is-hidden {
display: none !important;
}- 用
!important是为了确保能压过内联样式或其他高优先级规则 - 避免在 JS 里写
panel.style.display = 'none'—— 后续想加过渡动画或适配暗色模式时会卡住 - 如果需要保留占位空间,改用
visibility: hidden+ 单独类名,而非display
requestAnimationFrame 替代 setTimeout 做逐帧动画
滚动视差、数字滚动计数、进度条填充等需要平滑变化的效果,用 setTimeout 容易掉帧或卡顿。浏览器对 requestAnimationFrame 有优化调度:
JS特效就是网页中实现的特殊效果或者特殊的功能的一种技术,是用网页脚本(javascript)来编写制作动态特殊效果,比如图片切换,渐变等等,它为网页活跃了网页的气氛,有时候会起到一定的亲切力。务(控制台应用程序、桌面应用程序、WEB应用程序等)
立即学习“Java免费学习笔记(深入)”;
function animateCounter(el, target, current = 0) {
if (current >= target) {
el.textContent = target;
return;
}
const step = Math.ceil((target - current) / 20);
el.textContent = Math.min(current + step, target);
requestAnimationFrame(() => animateCounter(el, target, Number(el.textContent)));
}- 不要用
for循环 +setTimeout模拟动画 —— 事件队列堆积会导致延迟不可控 -
requestAnimationFrame自动匹配屏幕刷新率(通常是 60fps),且标签页非激活时会暂停,省资源 - 数值类动画务必用
Number()转类型,避免字符串拼接(如'10' + 1 === '101')
监听 scroll 或 resize 时必须节流
这些事件在用户操作中高频触发(每秒几十次),不加限制直接执行 DOM 操作会严重拖慢页面:
let isThrottled = false;
window.addEventListener('scroll', () => {
if (isThrottled) return;
isThrottled = true;
doStickyHeaderLogic();
setTimeout(() => isThrottled = false, 16); // ≈ 60fps 一帧
});- 用
setTimeout+ 标志位比 Lodash 的throttle更轻量,适合简单场景 - 别在
scroll回调里调用getBoundingClientRect()或offsetTop—— 触发强制同步布局(Layout Thrashing) - 现代方案可考虑
IntersectionObserver替代 scroll 监听做懒加载或吸顶,它本身已内置性能优化
真正难的不是写出动效,而是判断该不该动、何时停、怎么退化。比如悬停菜单在触摸设备上没 hover,就得 fallback 到点击展开;又比如动画在低性能设备上应自动降级为 class 切换而非逐帧计算。这些细节不在语法里,而在运行时环境的判断中。









