一个简易版无缝轮播图的实现思路

一个简易版无缝轮播图的实现思路

轮播图应该是每个前端的入门项目了,但是轮播图的无缝切换却难住了不少人,并且我在最近的面试中也被问到了,所以本文将介绍一个简易版的无缝轮播图的实现思路。

思路

无缝轮播图的难点无非就是第一张图和最后一张图的无缝过渡,解决好这一点,剩下的就没什么难度了。

具体实现思路:

  1. 在第一张图的的前面加一张和最后一张一样的图,同样的,在最后一张图的后面加一张和第一张一样的图。类似下图:
  2. 当划到最后一张图 copy-1 时,将过渡动画关闭,瞬间切换到 1 图
  3. 同理,当划到第一张图 copy-n 时,将过渡动画关闭,瞬间切换到 n 图

具体实现:

首先我们准备好以下元素:

html 复制代码
<div class="banner">
  <button class="left-arrow"><</button>
  <div class="banner-wrapper">
    <div class="banner-wrapper-item banner-copy3">copy-3</div>
    <div class="banner-wrapper-item banner-1">1</div>
    <div class="banner-wrapper-item banner-2">2</div>
    <div class="banner-wrapper-item banner-3">3</div>
    <div class="banner-wrapper-item banner-copy1">copy-1</div>
  </div>
  <button class="right-arrow">></button>
</div>
  • banner:轮播图的容器
  • left-arrow:左箭头
  • banner-wrapper:轮播图的内部容器,里面放置了五张图片,这里使用 div 来代替 img
  • banner-wrapper-item:轮播图的每一张图片,其中 banner-copy1 和 banner-copy3 是第一张和最后一张图片的复制品
  • right-arrow:右箭头

然后我们给它们分别添加样式:

css 复制代码
.banner {
  margin: 0 auto;
  width: 200px;
  height: 200px;
  border: 1px solid rgb(0, 0, 0);
  overflow: hidden;
  position: relative;
}

.banner-wrapper {
  display: flex;
  transition: transform 0.5s ease-in-out;
  transform: translateX(-200px); /* 初始位置 */
}

.banner-wrapper-item {
  flex-shrink: 0;
  width: 200px; /* 图片宽度 */
  height: 200px; /* 图片高度 */
}

.banner-copy3 {
  background-color: rgb(154, 170, 212);
}

.banner-1 {
  background-color: rgb(168, 230, 166);
}

.banner-2 {
  background-color: rgb(209, 174, 174);
}

.banner-3 {
  background-color: rgb(154, 170, 212);
}

.banner-copy1 {
  background-color: rgb(168, 230, 166);
}

.left-arrow {
  position: absolute;
  top: 50%;
  left: 0;
  transform: translateY(-50%);
  outline: none;
  border: none;
  cursor: pointer;
  z-index: 99;
}

.right-arrow {
  position: absolute;
  top: 50%;
  right: 0;
  transform: translateY(-50%);
  outline: none;
  border: none;
  cursor: pointer;
  z-index: 99;
}

我们给 banner 容器设置宽高为 200pxoverflowhidden,并设置 position: relative,方便后面控制 transform

banner-wrapper 设置 display: flex,让内部元素并排排布,通过控制 translateX 来实现图片的切换,并加上过渡效果。

给每个 item 设置宽度和高度为 200px,并设置背景色。

left-arrowright-arrow 设置位置和大小。

获取需要用到的元素:

javascript 复制代码
const bannerWrapper = document.querySelector('.banner-wrapper');
const leftArrow = document.querySelector('.left-arrow');
const rightArrow = document.querySelector('.right-arrow');

定义一些变量:

javascript 复制代码
const length = bannerWrapper.children.length; // 图片数量 加上前后复制的一张共五张
let cur = 1; // 当前图片索引,从 0 开始
let width = 200; // 图片宽度

重点来了,给 left-arrowright-arrow 绑定点击事件。

具体讲一下里面的逻辑,以右箭头为例:

  1. 首先判断当前所以图片是否为最后一张,如果是,则将当前图片索引设置为 1,并关闭过渡动画,瞬间切换图片 1
  2. 当切换到图片 1 后,再将当前图片索引加 1,并开启过渡动画,切换到图片 2 ,这里需要注意,这里需要用 setTimeout 函数包一下,不然两次的切换会合并到一起
  3. 如果不是最后一张,则将当前图片索引加 1,并设置 transform 值,使得图片切换到下一张。

左箭头同理,下面是具体的代码:

javascript 复制代码
// 给右箭头绑定点击事件
rightArrow.addEventListener('click', () => {
  if (cur === length - 1) {
    cur = 1;
    bannerWrapper.style.transition = 'none';
    bannerWrapper.style.transform = `translateX(-${cur * width}px)`;
    setTimeout(() => {
      // 让上一个切换完成在执行下一个切换
      cur++;
      bannerWrapper.style.transition = 'transform 0.5s ease-in-out';
      bannerWrapper.style.transform = `translateX(-${cur * width}px)`;
    }, 0);
    return;
  }
  cur++;
  bannerWrapper.style.transform = `translateX(-${cur * width}px)`;
});

// 给左箭头绑定点击事件
leftArrow.addEventListener('click', () => {
  if (cur === 0) {
    cur = length - 2;
    bannerWrapper.style.transition = 'none';
    bannerWrapper.style.transform = `translateX(-${cur * width}px)`;
    setTimeout(() => {
      // 让上一个切换完成在执行下一个切换
      cur--;
      bannerWrapper.style.transition = 'transform 0.5s ease-in-out';
      bannerWrapper.style.transform = `translateX(-${cur * width}px)`;
    }, 0);
    return;
  }
  cur--;
  bannerWrapper.style.transform = `translateX(-${cur * width}px)`;
});

到此,一个简单的无缝切换轮播图就完成了。

当然后续还可以加上定时切换和滑动切换的功能,不过无缝轮播的思路都差不多,感兴趣的可以实现一下。

如果有更好的实现方法,欢迎交流。

相关推荐
Senar33 分钟前
如何判断浏览器是否开启硬件加速
前端·javascript·数据可视化
HtwHUAT1 小时前
实验四 Java图形界面与事件处理
开发语言·前端·python
利刃之灵1 小时前
01-初识前端
前端
天天扭码1 小时前
一分钟解决 | 高频面试算法题——最大子数组之和
前端·算法·面试
全宝2 小时前
🌏【cesium系列】01.vue3+vite集成Cesium
前端·gis·cesium
拉不动的猪2 小时前
简单回顾下插槽透传
前端·javascript·面试
烛阴2 小时前
Fragment Shader--一行代码让屏幕瞬间变黄
前端·webgl
爱吃鱼的锅包肉2 小时前
Flutter路由模块化管理方案
前端·javascript·flutter
风清扬雨3 小时前
Vue3具名插槽用法全解——从零到一的详细指南
前端·javascript·vue.js