两边预览轮播图需克隆首尾图并用transform位移实现:扩展数组为[last,...original,first],容器宽为单图×3,初始translatex=-单图宽;维护realindex与domindex映射;共享定时器并统一清除重启;滑动切换仅在touchend依方向阈值判定。

用 transform + 克隆首尾图实现两边预览效果
两边有预览的轮播图,本质是让当前图居中、左右各露出一张相邻图的边缘。这不能靠 opacity 或 display 切换实现,必须用 transform: translateX() 位移 + DOM 克隆来撑开可视范围。
核心做法是:把原始图片数组扩展成 [last, ...original, first](克隆末尾图到开头、首图到末尾),再让容器宽度设为单图宽 × 3,初始位移设为 -单图宽,这样用户看到的就是「左预览|当前|右预览」三张图的视口。
- 克隆操作必须在 JS 初始化时完成,不能靠 CSS 伪元素模拟——
::before/::after无法插入真实<img>,无法响应加载或懒加载 - 单图宽度建议用
getBoundingClientRect().width动态读取,避免写死像素值导致响应式错位 - 容器需设
overflow: hidden,否则克隆图会溢出显示干扰布局 - 不要用
left或margin-left做位移——它们触发重排,动画卡顿,且不支持will-change: transform硬件加速
左右按钮点击时的索引映射必须修正
DOM 中有 n + 2 张图(n 是原始图数),但用户只该感知 n 个逻辑位置。点击“下一张”时,视觉上从第 0 张切到第 1 张,实际 DOM 索引是从 1 移动到 2(因为开头多了一张克隆图)。
所以你需要维护两个索引:
-
realIndex:用户看到的 0~n−1 范围,用于更新指示点、判断是否到头/结尾 -
domIndex:真实 DOM 位置,范围是 1~n(对应克隆后数组的中间 n 项),用于计算translateX值
例如原始 3 张图,克隆后 DOM 顺序是 [img2, img0, img1, img2, img0](假设索引 0/1/2),那么当 realIndex === 0 时,domIndex 应为 1;realIndex === 2 时,domIndex 应为 3。这个映射关系必须在每次点击前算清楚,否则左右预览会突然跳空或错位。
自动轮播与手动切换必须共享同一计时器引用
如果用户点了一次右箭头,接着自动轮播又执行一次切换,就会出现「刚切到第 2 张,0.8 秒后又切到第 3 张」的节奏混乱。这不是功能叠加问题,而是状态没同步。
- 全局声明
let carouselTimer = null,所有启动定时器的地方(startAutoPlay()、mouseLeave、页面加载后)都先执行clearInterval(carouselTimer) - 每次按钮点击后,立刻调用
clearInterval(carouselTimer),再立即用新起始位置重启定时器 - 别用
setTimeout递归模拟轮播——堆栈不可控,暂停/恢复逻辑难统一,且无法被外部中断
另外,鼠标悬停暂停必须监听容器的 mouseenter/mouseleave,而不是按钮本身——用户可能悬停在预览区域,但没碰到按钮,此时仍需暂停。
移动端 touch 滑动要加方向阈值和 preventDefault
手指一滑就触发切换,极易误触。真正可用的滑动切换,关键在 touchend 那一刻的方向判定,不是跟踪过程。
- 在
touchstart记录e.touches[0].clientX - 在
touchend再读一次e.changedTouches[0].clientX,算差值 - 差值绝对值
就忽略(防抖);差值 <code>> 50且为负 → 向左滑 → 触发 next;为正 → 向右滑 → 触发 prev - 必须在
touchstart和touchmove中调用e.preventDefault(),否则 iOS 会同时触发页面滚动,造成撕裂感
注意:不要在 touchmove 里实时更新 translateX——那是拖拽预览逻辑,和轮播切换是两套系统。两边预览轮播只响应「松手后的方向决策」,不响应「滑动过程」。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











