轮播图需结构化容器体系,外层.carousel约束尺寸与溢出,内层.carousel-track用flex布局并设子项flex-shrink:0,每张图须包裹在.carousel-item中,轨道宽度=单图宽×总数,指示器和按钮须为.carousel直接子元素且与索引同步,初始化须在domcontentloaded后执行。

轮播图能动起来,前提是 HTML 结构本身不“散架”——它不是一堆 <img> 的简单堆砌,而是一个有层级、有职责分工的容器体系。
为什么不能直接写一串 <img> 标签?
常见错误是把图片平铺在 里:<img src="1.jpg"><img src="2.jpg"><img src="3.jpg">。这样 JS 拿不到统一父容器,无法批量控制显隐;CSS 也没法用 overflow: hidden 截断溢出,更没法靠 transform 做位移动画。
必须用一个外层 <div class="carousel"> 包住所有内容,再用一个轨道容器(如 <code><div class="carousel-track">)承载图片项。这个轨道要能撑开宽度、支持 flex 排列、响应 JS 的 <code>translateX() 调整。
<div class="carousel">:负责定位、尺寸约束和 <code>overflow: hidden<div class="carousel-track">:必须设 <code>display: flex,且子项(每张图)需设flex-shrink: 0防止被压缩- 每张图必须包裹在独立容器中(如
<div class="carousel-item"><img></div>),不能裸放<img>—— 否则无法统一加 class 控制状态或过渡 - 推荐用
slides[0].getBoundingClientRect().width获取真实渲染宽度 - 如果图片宽高不一致,
getBoundingClientRect()比clientWidth更可靠 - 初始化时就计算好
slideWidth并缓存,避免每次切换都重复读取 DOM - 移动端要注意视口缩放(
devicePixelRatio不影响该值,但 zoom 会) - 所有控制元素(
.carousel-dots、.carousel-prev、.carousel-next)必须是.carousel的直接子元素 - 指示器应由 JS 动态生成,并基于
slides.length创建对应数量的<button class="dot"></button>,而非手写固定三个 - 按钮点击后调用的
goToSlide()必须先校验索引范围,否则slides[5]在只有 3 张图时会返回undefined - 悬停暂停自动播放时,
clearInterval和重启逻辑必须作用于同一个 timer 变量,否则旧定时器还在跑
carousel-track 的宽度和 transform 怎么对齐?
轨道宽度必须等于「单张图宽 × 图片总数」,否则 translateX(-currentIndex * slideWidth) 会偏移错位。但注意:别用 offsetWidth 或 clientWidth 直接读取,它们可能受边框、滚动条干扰。
指示器(dots)和按钮怎么跟结构绑定才不脱节?
指示器和左右按钮不是装饰,它们的 DOM 位置和事件逻辑必须与 .carousel-track 的索引严格同步。一旦结构松散,比如指示器放在 顶层,JS 就容易因查询顺序或时机错乱导致 active 状态错位。
最常被忽略的是结构初始化时机:DOM 必须完全加载完毕再执行 JS 初始化,否则 querySelectorAll('.carousel-track img') 可能为空。别依赖 window.onload——它等资源(如图片)加载完才触发,太晚;用 DOMContentLoaded 才是正解。











