JS实现超简易轮播图

2023-09-23 15:13:15 浏览数 (2)

0.示例

预览地址: https://codepen.io/klren0312/full/ymvEbr

2

1.画界面

1.画显示区域

首先就是画个固定的区域, 用来展示轮播图当前能看到的图, 其余超出的部分, 使用 overflow: hidden 隐藏.

代码语言:javascript复制
.box {
  width: 300px;
  height: 200px;
  overflow: hidden;
}
代码语言:javascript复制
<div class="box"></div>
2.画轮播图主体

假设五张图, 将他们横向排列(图片太麻烦, 我就css画了, 有些样式可以忽略)

image.png

代码语言:javascript复制
.swiper {
  position: relative;
  width: 1500px;
  height: 200px;
}

.swiper .swiper-item {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 300px;
  height: 100%;
  float: left;
  box-sizing: border-box;
  background: #efefef;
  border: 1px solid #333;
}

// 两个div区分一下
.swiper .swiper-item:nth-child(2n) {
  background: #fff;
}
代码语言:javascript复制
<div class="box">
  <div class="swiper">
    <div class="swiper-item">1</div>
    <div class="swiper-item">2</div>
    <div class="swiper-item">3</div>
    <div class="swiper-item">4</div>
    <div class="swiper-item">5</div>
  </div>
</div>

这样, 样式部分就搞定了

2.轮播JS代码

1.原理

由于轮播图已经横向排列, 所以只要控制.swiper向x轴偏移距离, 就可以实现图片切换, 这里使用transformtranslate属性来控制x轴偏移.可以通过transition来设置过渡动画

问题与难点: 当轮播图到达最后一个图片时, 需要平滑切换到第一张, 如果没有过渡动画倒无所谓, 否则将会出现从最后一张快速倒回第一张的动画, 降低体验.

解决方法: 初始化的时候, 复制第一位图片放在最后一位;复制原来最后一位图片, 放到第一位.当然如果你只往右切换, 则不用将第一位放在最后一位.示例如下(数字代表图片顺序): 初始排列:

代码语言:javascript复制
|1|2|3|4|5|

初始化后排列:

代码语言:javascript复制
|5|1|2|3|4|5|1|
2.代码片段

代码使用ES6语法, 这些无所谓, 具体逻辑知道就行

1.构造器

构造器接收一个变量, 切换轮播图的延时.

在构造器里新建了一些常量, 轮播图的DOM, 轮播图片的DOM数组, 轮播图的个数(注意是没有初始化前的图片个数), 以及赋值延时(默认是1000ms)

随后调用初始化函数

代码语言:javascript复制
constructor (delay = 1000) {
  this.swiper = document.querySelector('.swiper') // 轮播图
  this.swiperItemList = document.querySelectorAll('.swiper-item') // 轮播项
  this.totalLength = this.swiperItemList.length // 轮播图个数
  this.delay = delay
  this.init()
}
2.初始化函数

复制第一位图片放在最后一位;复制原来最后一位图片, 放到第一位;即 12345 => 5123451. 随后, 将轮播图显示的位置定在第一张图片位置, 即1的位置 currentPosition变量用于标记当前滚动的图片

代码语言:javascript复制
init () {
  // 将轮播图第一项克隆, 并放在最后
  const cloneFirst = document.querySelectorAll('.swiper-item')[0].cloneNode(true)
  this.swiper.appendChild(cloneFirst)
  // 因为 totalLength 是原始的轮播图个数, 所以可以正确定位到原来的轮播图最后一个
  const cloneLast = document.querySelectorAll('.swiper-item')[this.totalLength - 1].cloneNode(true)
  this.swiper.insertBefore(cloneLast, this.swiper.firstChild)
  // 设置轮播图总长, 加上新加的两个
  this.swiper.style.width = (this.totalLength   2) * 300   'px'
  // 当前轮播图位置分布为  5 12345 1
  // 初始化轮播图为 1 位置
  this.currentPosition = 1
  this.swiper.style.transform = `translateX(${-this.currentPosition * 300}px`
}
3.滚动动画

滚动时, 给.swiper标记一个isAnimating的class,来标明正在滚动. 给.swiper设置x轴偏移位置, 以及添加过渡动画. 滚动的延时使用设定的delay, 延时结束后, 清除过渡动画(过渡动画的清除, 主要给后面最后一位跳到第一位时用)和isAnimating标记

代码语言:javascript复制
goSlider () {
  // 添加过渡效果, delay 需要一致; 位置偏移一个单位
  this.swiper.style.transition = `transform ${this.delay / 1000}s ease`
  this.swiper.style.transform = `translateX(${-this.currentPosition * 300}px`
  // 添加正在切换的class, 给上面 animate 方法用来判断
  this.swiper.classList.add('isAnimating')
  // 切换结束, 清空状态, 清空过渡效果
  setTimeout(() => {
    this.swiper.style.transition = ''
    this.swiper.classList.remove('isAnimating')
  }, this.delay)
}
4.轮播操作

判断滚动的位置, 若在最后一位即第5位, 则将定位改为与之相同的第0位, 并进行偏移.然后将位数加1, 到第1位. 此时没有过渡动画, 就实现了最后一位5和第一位5的快速切换, 然后过渡到第1位;

currentPosition设置为1后, 进入到切换动画, 这样视觉上就是5过渡到1

代码语言:javascript复制
animate () {
  // 如果正在切换, 则不动
  if (this.swiper.classList.contains('isAnimating')) return
  // 如果在第五项, 则将定位改为第 0 项, 并设置位置, 此时没有 transition 动画, 秒切
  if (this.currentPosition === this.totalLength) {
    this.currentPosition = 0
    this.swiper.style.transform = `translateX(${-this.currentPosition * 300}px`
  }
  // 将位置设为第一项
  this.currentPosition  
  // 轮播
  setTimeout(() => {
    this.goSlider()
  }, 20)
}
5.轮播开始

循环调用轮播操作函数

代码语言:javascript复制
start () {
  setInterval(() => this.animate(),this.delay)
}

3.使用这个轮播class

代码语言:javascript复制
window.onload = function () {
  const slider = new SliderBox(2000)
  slider.start()
}

4.整体代码

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    .box {
      width: 300px;
      height: 200px;
      overflow: hidden;
    }

    .swiper {
      position: relative;
      width: 1500px;
      height: 200px;
    }

    .swiper .swiper-item {
      display: flex;
      justify-content: center;
      align-items: center;
      width: 300px;
      height: 100%;
      float: left;
      box-sizing: border-box;
      background: #efefef;
      border: 1px solid #333;
    }

    .swiper .swiper-item:nth-child(2n) {
      background: #fff;
    }
  </style>
</head>

<body>
  <div class="box">
    <div class="swiper">
      <div class="swiper-item">1</div>
      <div class="swiper-item">2</div>
      <div class="swiper-item">3</div>
      <div class="swiper-item">4</div>
      <div class="swiper-item">5</div>
    </div>
  </div>
  <script>
    class SliderBox {
      /**
       * 构造器
       * @param {number} delay 切换延时
       */
      constructor(delay = 1000) {
        this.swiper = document.querySelector('.swiper') // 轮播图
        this.swiperItemList = document.querySelectorAll('.swiper-item') // 轮播项
        this.totalLength = this.swiperItemList.length // 轮播图个数
        this.delay = delay
        this.init()
      }
      /**
       * 初始化配置
       */
      init() {
        // 将轮播图第一项克隆, 并放在最后
        const cloneFirst = document.querySelectorAll('.swiper-item')[0].cloneNode(true)
        this.swiper.appendChild(cloneFirst)
        // 因为 totalLength 是原始的轮播图个数, 所以可以正确定位到原来的轮播图最后一个
        const cloneLast = document.querySelectorAll('.swiper-item')[this.totalLength - 1].cloneNode(true)
        this.swiper.insertBefore(cloneLast, this.swiper.firstChild)
        // 设置轮播图总长, 加上新加的两个
        this.swiper.style.width = (this.totalLength   2) * 300   'px'
        // 当前轮播图位置分布为  5 12345 1
        // 初始化轮播图为 1 位置
        this.currentPosition = 1
        this.swiper.style.transform = `translateX(${-this.currentPosition * 300}px`
      }
      /**
       * 切换动画
       */
      animate() {
        // 如果正在切换, 则不动
        if (this.swiper.classList.contains('isAnimating')) return
        // 如果在第五项, 则将定位改为第 0 项, 并设置位置, 此时没有 transition 动画, 秒切
        if (this.currentPosition === this.totalLength) {
          this.currentPosition = 0
          this.swiper.style.transform = `translateX(${-this.currentPosition * 300}px`
        }
        // 将位置设为第一项
        this.currentPosition  
        // 轮播
        setTimeout(() => {
          this.goSlider()
        }, 20)
      }
      /**
       * 轮播
       */
      goSlider() {
        // 添加过渡效果, delay 需要一致; 位置偏移一个单位
        this.swiper.style.transition = `transform ${this.delay / 1000}s ease`
        this.swiper.style.transform = `translateX(${-this.currentPosition * 300}px`
        // 添加正在切换的class, 给上面 animate 方法用来判断
        this.swiper.classList.add('isAnimating')
        // 切换结束, 清空状态, 清空过渡效果
        setTimeout(() => {
          this.swiper.style.transition = ''
          this.swiper.classList.remove('isAnimating')
        }, this.delay)
      }
      /**
       * 开始轮播
       */
      start() {
        setInterval(() => this.animate(), this.delay)
      }
    }
  </script>
  <script>
    window.onload = function () {
      const slider = new SliderBox(2000)
      slider.start()
    }
  </script>
</body>

</html>

0 人点赞