JavaScript 轮播图实现的五种主流方式

0 阅读4分钟

一、原生 JS 定时切换(基础版)

实现思路:通过 setInterval 定时切换图片索引,结合按钮手动控制,利用 CSS opacity 实现显隐过渡。

HTML 结构

 <div class="carousel-basic">
   <div class="carousel-images">
     <img src="image1.jpg" alt="Image 1" class="active">
     <img src="image2.jpg" alt="Image 2">
     <img src="image3.jpg" alt="Image 3">
   </div>
   <button class="prev-btn">上一张</button>
   <button class="next-btn">下一张</button>
 </div>

CSS 样式

 .carousel-basic {
   position: relative;
   width: 600px;
   height: 400px;
   overflow: hidden;
   margin: 0 auto;
 }
 .carousel-basic .carousel-images img {
   position: absolute;
   width: 100%;
   height: 100%;
   opacity: 0;
   transition: opacity 0.5s;
   object-fit: cover;
 }
 .carousel-basic .carousel-images img.active {
   opacity: 1;
 }
 .carousel-basic button {
   position: absolute;
   top: 50%;
   transform: translateY(-50%);
   background: rgba(0,0,0,0.5);
   color: white;
   border: none;
   padding: 10px 20px;
   cursor: pointer;
 }
 .carousel-basic .prev-btn { left: 10px; }
 .carousel-basic .next-btn { right: 10px; }

JavaScript

 // 1. 获取DOM元素,定位轮播容器、图片、按钮
 const carouselBasic = document.querySelector('.carousel-basic');
 const images = carouselBasic.querySelectorAll('.carousel-images img');
 const prevBtn = carouselBasic.querySelector('.prev-btn');
 const nextBtn = carouselBasic.querySelector('.next-btn');
 // 当前显示的图片索引,初始为0(第一张图)
 let currentIndex = 0;
 // 自动播放定时器,用于后续清除
 let timer;
 ​
 // 2. 核心方法:根据索引显示对应图片,隐藏其他图片
 function showImage(index) {
   // 遍历所有图片,移除active类(隐藏)
   images.forEach(img => img.classList.remove('active'));
   // 给目标索引的图片添加active类(显示)
   images[index].classList.add('active');
 }
 ​
 // 3. 下一张图片:索引自增,取余实现循环(最后一张后回到第一张)
 function nextImage() {
   currentIndex = (currentIndex + 1) % images.length;
   showImage(currentIndex);
 }
 ​
 // 4. 上一张图片:索引自减,加图片长度再取余,避免负索引
 function prevImage() {
   currentIndex = (currentIndex - 1 + images.length) % images.length;
   showImage(currentIndex);
 }
 ​
 // 5. 自动播放:3秒切换一次图片
 function startAutoPlay() {
   timer = setInterval(nextImage, 3000);
 }
 ​
 // 6. 停止自动播放:清除定时器
 function stopAutoPlay() {
   clearInterval(timer);
 }
 ​
 // 7. 绑定上一张按钮点击事件:停止自动播放→切换图片→重新开启自动播放
 prevBtn.addEventListener('click', () => {
   stopAutoPlay();
   prevImage();
   startAutoPlay();
 });
 ​
 // 8. 绑定下一张按钮点击事件:逻辑同上
 nextBtn.addEventListener('click', () => {
   stopAutoPlay();
   nextImage();
   startAutoPlay();
 });
 ​
 // 9. 初始化:显示第一张图,开启自动播放
 showImage(currentIndex);
 startAutoPlay();

二、CSS3 Transition + JS 控制(流畅版)

实现思路:利用 CSS3 transition 属性实现平滑位移过渡,JS 控制 transform 改变图片轨道位置,比基础版动画更流畅。

HTML 结构

 <div class="carousel-smooth">
   <div class="carousel-track">
     <img src="image1.jpg" alt="Image 1">
     <img src="image2.jpg" alt="Image 2">
     <img src="image3.jpg" alt="Image 3">
   </div>
   <button class="prev-btn">上一张</button>
   <button class="next-btn">下一张</button>
 </div>

CSS 样式

 .carousel-smooth {
   position: relative;
   width: 600px;
   height: 400px;
   overflow: hidden;
   margin: 0 auto;
 }
 .carousel-smooth .carousel-track {
   display: flex;
   width: 300%; /* 3张图总宽度,每张占100%容器宽度 */
   height: 100%;
   transition: transform 0.5s ease-in-out; /* 核心:平滑位移过渡 */
 }
 .carousel-smooth .carousel-track img {
   width: 600px; /* 单张图宽度与容器一致 */
   height: 100%;
   object-fit: cover;
 }
 .carousel-smooth button {
   position: absolute;
   top: 50%;
   transform: translateY(-50%);
   background: rgba(0,0,0,0.5);
   color: white;
   border: none;
   padding: 10px 20px;
   cursor: pointer;
 }
 .carousel-smooth .prev-btn { left: 10px; }
 .carousel-smooth .next-btn { right: 10px; }

JavaScript

 // 1. 获取DOM元素,定位轮播容器、图片轨道、图片、按钮
 const carouselSmooth = document.querySelector('.carousel-smooth');
 const track = carouselSmooth.querySelector('.carousel-track');
 const imagesSmooth = carouselSmooth.querySelectorAll('.carousel-track img');
 const prevBtnSmooth = carouselSmooth.querySelector('.prev-btn');
 const nextBtnSmooth = carouselSmooth.querySelector('.next-btn');
 // 当前显示的图片索引,初始为0
 let currentIndexSmooth = 0;
 // 容器宽度(与CSS一致,控制轨道位移距离)
 const width = 600;
 // 自动播放定时器
 let timerSmooth;
 ​
 // 2. 核心方法:更新轨道位置,通过transform实现位移
 function updateTrack() {
   // 位移距离 = 当前索引 × 容器宽度,负号表示向左位移
   track.style.transform = `translateX(-${currentIndexSmooth * width}px)`;
 }
 ​
 // 3. 下一张图片:索引自增,取余循环
 function nextImageSmooth() {
   currentIndexSmooth = (currentIndexSmooth + 1) % imagesSmooth.length;
   updateTrack(); // 触发轨道位移,CSS过渡生效
 }
 ​
 // 4. 上一张图片:索引自减,避免负索引
 function prevImageSmooth() {
   currentIndexSmooth = (currentIndexSmooth - 1 + imagesSmooth.length) % imagesSmooth.length;
   updateTrack();
 }
 ​
 // 5. 自动播放:3秒切换一次
 function startAutoPlaySmooth() {
   timerSmooth = setInterval(nextImageSmooth, 3000);
 }
 ​
 // 6. 停止自动播放:清除定时器
 function stopAutoPlaySmooth() {
   clearInterval(timerSmooth);
 }
 ​
 // 7. 绑定上一张按钮事件:停止自动播放→切换→重启
 prevBtnSmooth.addEventListener('click', () => {
   stopAutoPlaySmooth();
   prevImageSmooth();
   startAutoPlaySmooth();
 });
 ​
 // 8. 绑定下一张按钮事件:逻辑同上
 nextBtnSmooth.addEventListener('click', () => {
   stopAutoPlaySmooth();
   nextImageSmooth();
   startAutoPlaySmooth();
 });
 ​
 // 9. 初始化:开启自动播放
 startAutoPlaySmooth();

三、面向对象封装(可复用版)

实现思路:将轮播图功能封装为 Carousel 类,支持配置参数(自动播放、间隔时间、宽度等),可实例化多个轮播图,复用性强。

HTML 结构

 <div class="carousel-oop" id="carousel1">
   <div class="carousel-track">
     <img src="image1.jpg" alt="Image 1">
     <img src="image2.jpg" alt="Image 2">
     <img src="image3.jpg" alt="Image 3">
   </div>
   <button class="prev-btn">上一张</button>
   <button class="next-btn">下一张</button>
 </div>

CSS 样式

 .carousel-oop {
   position: relative;
   width: 600px;
   height: 400px;
   overflow: hidden;
   margin: 0 auto;
 }
 .carousel-oop .carousel-track {
   display: flex;
   height: 100%;
   transition: transform 0.5s ease-in-out;
 }
 .carousel-oop .carousel-track img {
   width: 600px;
   height: 100%;
   object-fit: cover;
 }
 .carousel-oop button {
   position: absolute;
   top: 50%;
   transform: translateY(-50%);
   background: rgba(0,0,0,0.5);
   color: white;
   border: none;
   padding: 10px 20px;
   cursor: pointer;
 }
 .carousel-oop .prev-btn { left: 10px; }
 .carousel-oop .next-btn { right: 10px; }

JavaScript

 // 1. 封装Carousel类,统一管理轮播逻辑,支持自定义配置
 class Carousel {
   // 构造函数:接收轮播容器元素和配置参数(默认空对象)
   constructor(element, options = {}) {
     // 绑定DOM元素
     this.container = element;
     this.track = this.container.querySelector('.carousel-track');
     this.images = this.container.querySelectorAll('.carousel-track img');
     this.prevBtn = this.container.querySelector('.prev-btn');
     this.nextBtn = this.container.querySelector('.next-btn');
     
     // 2. 合并默认配置与用户配置,用户配置优先级更高
     this.options = {
       autoPlay: true, // 默认自动播放
       interval: 3000, // 默认切换间隔3秒
       width: 600, // 默认容器宽度600px
       ...options
     };
     
     // 初始化状态
     this.currentIndex = 0; // 当前图片索引
     this.timer = null; // 自动播放定时器
     
     // 3. 初始化执行(轨道宽度、事件绑定)
     this.init();
   }
   
   // 4. 初始化方法:完成轨道宽度设置、事件绑定
   init() {
     // 初始化轨道总宽度 = 图片数量 × 容器宽度
     this.track.style.width = `${this.images.length * this.options.width}px`;
     this.bindEvents(); // 绑定按钮、鼠标悬停事件
     // 若开启自动播放,初始化时启动
     if (this.options.autoPlay) this.startAutoPlay();
   }
   
   // 5. 核心方法:更新轨道位置,控制图片切换
   update() {
     this.track.style.transform = `translateX(-${this.currentIndex * this.options.width}px)`;
   }
   
   // 6. 下一张图片:索引循环自增
   next() {
     this.currentIndex = (this.currentIndex + 1) % this.images.length;
     this.update();
   }
   
   // 7. 上一张图片:索引循环自减
   prev() {
     this.currentIndex = (this.currentIndex - 1 + this.images.length) % this.images.length;
     this.update();
   }
   
   // 8. 开启自动播放:按配置间隔执行next方法
   startAutoPlay() {
     this.timer = setInterval(() => this.next(), this.options.interval);
   }
   
   // 9. 停止自动播放:清除定时器
   stopAutoPlay() {
     clearInterval(this.timer);
   }
   
   // 10. 事件绑定:统一管理所有交互事件
   bindEvents() {
     // 上一张按钮点击事件
     this.prevBtn.addEventListener('click', () => {
       this.stopAutoPlay();
       this.prev();
       if (this.options.autoPlay) this.startAutoPlay();
     });
     
     // 下一张按钮点击事件
     this.nextBtn.addEventListener('click', () => {
       this.stopAutoPlay();
       this.next();
       if (this.options.autoPlay) this.startAutoPlay();
     });
     
     // 鼠标悬停暂停,离开继续播放(优化体验)
     this.container.addEventListener('mouseenter', () => this.stopAutoPlay());
     this.container.addEventListener('mouseleave', () => {
       if (this.options.autoPlay) this.startAutoPlay();
     });
   }
 }
 ​
 // 11. 实例化轮播图:传入容器元素和自定义配置
 const carousel1 = new Carousel(document.getElementById('carousel1'), {
   autoPlay: true,
   interval: 3000,
   width: 600
 });
 ​
 // 可实例化第二个轮播图(需新增对应HTML结构)
 // const carousel2 = new Carousel(document.getElementById('carousel2'), { ... });

四、无缝滚动轮播图(进阶版)

实现思路:核心是「复制第一张图追加到轨道末尾」,当轮播到复制的图片时,瞬间将轨道复位到初始位置(无过渡),实现视觉上的无缝循环。结合 CSS3 transition 平滑过渡,JS 控制索引切换与复位逻辑,支持自动播放、手动控制。

HTML 结构

 <div class="carousel-seamless">
   <div class="carousel-track">
     <img src="image1.jpg" alt="Image 1">
     <img src="image2.jpg" alt="Image 2">
     <img src="image3.jpg" alt="Image 3">
     <!-- 复制第一张图,用于无缝衔接 -->
   </div>
   <button class="prev-btn">上一张</button>
   <button class="next-btn">下一张</button>
 </div>

CSS 样式

 .carousel-seamless {
   position: relative;
   width: 600px;
   height: 400px;
   overflow: hidden;
   margin: 0 auto;
 }
 .carousel-seamless .carousel-track {
   display: flex;
   height: 100%;
   transition: transform 0.5s ease-in-out; /* 平滑过渡 */
 }
 .carousel-seamless .carousel-track img {
   width: 600px; /* 与容器宽度一致 */
   height: 100%;
   object-fit: cover;
   flex-shrink: 0; /* 禁止图片收缩,保证宽度一致,关键! */
 }
 .carousel-seamless button {
   position: absolute;
   top: 50%;
   transform: translateY(-50%);
   background: rgba(0,0,0,0.5);
   color: white;
   border: none;
   padding: 10px 20px;
   cursor: pointer;
   z-index: 10; /* 按钮置于顶层,避免被遮挡 */
 }
 .carousel-seamless .prev-btn { left: 10px; }
 .carousel-seamless .next-btn { right: 10px; }

JavaScript

 // 1. 获取DOM元素,定位轮播容器、轨道、图片、按钮
 const carouselSeamless = document.querySelector('.carousel-seamless');
 const track = carouselSeamless.querySelector('.carousel-track');
 const images = carouselSeamless.querySelectorAll('.carousel-track img');
 const prevBtn = carouselSeamless.querySelector('.prev-btn');
 const nextBtn = carouselSeamless.querySelector('.next-btn');
 // 容器宽度(与CSS一致)
 const width = 600;
 // 当前图片索引,初始为0
 let currentIndex = 0;
 // 自动播放定时器
 let timer;
 ​
 // 2. 无缝滚动核心步骤1:复制第一张图,追加到轨道末尾(视觉衔接关键)
 const firstImg = images[0].cloneNode(true); // 克隆第一张图,true表示复制子节点
 track.appendChild(firstImg); // 追加到轨道末尾
 // 更新图片集合(包含克隆的第一张图,共4张)
 const allImages = carouselSeamless.querySelectorAll('.carousel-track img');
 // 更新轨道总宽度 = 所有图片(原3张+克隆1张)× 容器宽度
 track.style.width = `${allImages.length * width}px`;
 ​
 // 3. 核心方法:更新轨道位置,控制位移
 function updateTrack() {
   track.style.transform = `translateX(-${currentIndex * width}px)`;
 }
 ​
 // 4. 下一张图片(无缝核心逻辑)
 function nextImage() {
   currentIndex++;
   updateTrack(); // 触发平滑过渡,向左位移
   // 关键判断:当轮播到克隆的第一张图(索引=原图片长度3)时
   if (currentIndex === images.length) {
     // 等待过渡完成(与CSS transition时间一致,500ms)
     setTimeout(() => {
       track.style.transition = 'none'; // 取消过渡,实现瞬间复位
       currentIndex = 0; // 索引重置为0(真正的第一张图)
       updateTrack(); // 瞬间移动到初始位置,无视觉卡顿
       // 重置过渡效果,保证下次切换正常平滑
       setTimeout(() => {
         track.style.transition = 'transform 0.5s ease-in-out';
       }, 10); // 延迟10ms,避免过渡冲突
     }, 500);
   }
 }
 ​
 // 5. 上一张图片(无缝核心逻辑)
 function prevImage() {
   // 关键判断:当前是第一张图(索引=0)时
   if (currentIndex === 0) {
     track.style.transition = 'none'; // 取消过渡
     currentIndex = images.length; // 索引设为克隆图的位置(3)
     updateTrack(); // 瞬间移动到克隆图位置
     // 延迟10ms,重新开启过渡,再切换到上一张(原最后一张图)
     setTimeout(() => {
       track.style.transition = 'transform 0.5s ease-in-out';
       currentIndex--;
       updateTrack();
     }, 10);
   } else {
     // 非第一张图,正常索引自减,平滑过渡
     currentIndex--;
     updateTrack();
   }
 }
 ​
 // 6. 自动播放:3秒切换一次
 function startAutoPlay() {
   timer = setInterval(nextImage, 3000);
 }
 ​
 // 7. 停止自动播放:清除定时器
 function stopAutoPlay() {
   clearInterval(timer);
 }
 ​
 // 8. 绑定上一张按钮事件:停止→切换→重启
 prevBtn.addEventListener('click', () => {
   stopAutoPlay();
   prevImage();
   startAutoPlay();
 });
 ​
 // 9. 绑定下一张按钮事件:逻辑同上
 nextBtn.addEventListener('click', () => {
   stopAutoPlay();
   nextImage();
   startAutoPlay();
 });
 ​
 // 10. 鼠标悬停暂停,离开继续(优化体验)
 carouselSeamless.addEventListener('mouseenter', stopAutoPlay);
 carouselSeamless.addEventListener('mouseleave', startAutoPlay);
 ​
 // 11. 初始化:开启自动播放
 startAutoPlay();

五、requestAnimationFrame 优化版

实现思路:用 requestAnimationFrame 替代 setInterval,避免定时器卡顿问题,结合时间戳控制切换间隔,动画更流畅、性能更优,适合高刷新率设备和复杂场景。

HTML 结构

 <div class="carousel-request">
   <div class="carousel-track">
     <img src="image1.jpg" alt="Image 1">
     <img src="image2.jpg" alt="Image 2">
     <img src="image3.jpg" alt="Image 3">
   </div>
   <button class="prev-btn">上一张</button>
   <button class=&#34;next-btn&#34;&gt;下一张&lt;/button&gt;&#xA;&lt;/div&gt;

CSS 样式

 .carousel-request {
   position: relative;
   width: 600px;
   height: 400px;
   overflow: hidden;
   margin: 0 auto;
 }
 .carousel-request .carousel-track {
   display: flex;
   height: 100%;
   transition: transform 0.5s ease-in-out;
 }
 .carousel-request .carousel-track img {
   width: 600px;
   height: 100%;
   object-fit: cover;
   flex-shrink: 0;
 }
 .carousel-request button {
   position: absolute;
   top: 50%;
   transform: translateY(-50%);
   background: rgba(0,0,0,0.5);
   color: white;
   border: none;
   padding: 10px 20px;
   cursor: pointer;
   z-index: 10;
 }
 .carousel-request .prev-btn { left: 10px; }
 .carousel-request .next-btn { right: 10px; }

JavaScript

 // 1. 获取DOM元素,定位容器、轨道、图片、按钮
 const carouselRequest = document.querySelector('.carousel-request');
 const track = carouselRequest.querySelector('.carousel-track');
 const images = carouselRequest.querySelectorAll('.carousel-track img');
 const prevBtn = carouselRequest.querySelector('.prev-btn');
 const nextBtn = carouselRequest.querySelector('.next-btn');
 // 容器宽度
 const width = 600;
 // 当前图片索引
 let currentIndex = 0;
 // 自动播放相关:时间戳(控制间隔)、请求动画ID(用于取消)
 let lastTime = 0;
 const interval = 3000; // 切换间隔3秒
 let requestId = null;
 ​
 // 2. 核心方法:更新轨道位置
 function updateTrack() {
   track.style.transform = `translateX(-${currentIndex * width}px)`;
 }
 ​
 // 3. 下一张图片:索引循环自增
 function nextImage() {
   currentIndex = (currentIndex + 1) % images.length;
   updateTrack();
 }
 ​
 // 4. 上一张图片:索引循环自减
 function prevImage() {
   currentIndex = (currentIndex - 1 + images.length) % images.length;
   updateTrack();
 }
 ​
 // 5. 自动播放核心:requestAnimationFrame 帧动画
 function autoPlay(timestamp) {
   // 时间戳判断:当前时间 - 上一次切换时间 ≥ 间隔时间,才执行切换
   if (!lastTime || timestamp - lastTime >= interval) {
     nextImage(); // 切换图片
     lastTime = timestamp; // 更新上一次切换时间戳
   }
   // 递归调用,实现持续帧动画(浏览器自动优化帧率)
   requestId = requestAnimationFrame(autoPlay);
 }
 ​
 // 6. 开启自动播放:启动帧动画
 function startAutoPlay() {
   // 先取消已有动画,避免重复启动
   if (requestId) cancelAnimationFrame(requestId);
   requestId = requestAnimationFrame(autoPlay);
 }
 ​
 // 7. 停止自动播放:取消帧动画
 function stopAutoPlay() {
   if (requestId) cancelAnimationFrame(requestId);
   requestId = null; // 重置请求ID
 }
 ​
 // 8. 绑定上一张按钮事件:停止→切换→重启
 prevBtn.addEventListener('click', () => {
   stopAutoPlay();
   prevImage();
   startAutoPlay();
 });
 ​
 // 9. 绑定下一张按钮事件:逻辑同上
 nextBtn.addEventListener('click', () => {
   stopAutoPlay();
   nextImage();
   startAutoPlay();
 });
 ​
 // 10. 鼠标悬停暂停,离开继续
 carouselRequest.addEventListener('mouseenter', stopAutoPlay);
 carouselRequest.addEventListener('mouseleave', startAutoPlay);
 ​
 // 11. 初始化:开启高性能自动播放
 startAutoPlay();