为什么图片切换容易“看起来卡”
图片切换特效的本质是连续改变元素的可见性、位置或透明度。卡顿通常来自两处:一是用定时器直接修改 left、width 等触发布局的属性;二是大图未预加载,切换瞬间才开始解码。把这两点处理好,多数特效就能顺滑。
用 CSS 过渡承担动画
最省事的做法是 JS 只负责切换状态,动画交给 CSS:
.slide { opacity: 0; transition: opacity .4s ease; }
.slide.active { opacity: 1; }
function show(index) {
slides.forEach((el, i) => el.classList.toggle(‘active’, i === index));
}
透明度和 transform 属于合成层属性,改动它们一般不会触发重排,适合淡入淡出和位移类切换。
淡入淡出与滑动两种基础特效
淡入淡出
给所有图片绝对定位叠放,通过切换 active 类控制 opacity。优点是实现简单、不依赖容器尺寸;缺点是同一时刻多张图参与合成,图多时要注意层级和 will-change 的滥用。
滑动切换
把图片横向排列在一个轨道容器里,改变 transform: translateX(-n * 100%)。滑动比淡入淡出更有方向感,且只移动一个容器,合成成本低。注意容器要设 overflow: hidden,轨道设 display: flex。
定时器还是 requestAnimationFrame
setInterval 适合固定节奏的自动播放,但切换瞬间若页面在后台或主线程繁忙,节奏会漂移。需要逐帧插值的特效(如缓动滑动、拖拽跟随)应使用 requestAnimationFrame,它在每帧回调中读取时间差计算进度,页面不可见时自动暂停,更省电。
自动播放还要处理用户交互:鼠标悬停暂停、离开恢复,页面隐藏时用 visibilitychange 停掉计时器,避免后台空转。
预加载与内存管理
切换前把下一张图 new Image() 预加载,等 onload 后再触发切换,可避免首帧空白。图片较多时不要一次性全部解码,采用“当前 + 前后各一张”的窗口式加载。
单页应用里切换组件销毁时,记得清除定时器、移除事件监听、把 src 置空或释放 Image 引用,否则大图会一直占着内存。
几个容易被忽略的细节
- 切换期间加锁,防止快速点击导致状态错乱;
- 首尾循环时用克隆节点做无缝衔接,注意克隆节点的
aria-hidden; - 给容器设置固定宽高比,避免图片加载引起布局抖动;
- 尊重
prefers-reduced-motion,对动画敏感的用户直接切换不做过渡。
把这些点落实到代码里,js图片切换特效 就不只是“能动”,而是稳定、流畅、可维护。