纯 CSS,原生 JavaScript,jQuery,Vue,React 实现轮播图, 一篇文章帮你全部搞定

纯 CSS,原生 JavaScript,jQuery,Vue,React 实现轮播图, 一篇文章帮你全部搞定_第1张图片


轮播图在平常的网页开发中十分常见,特别是电商类的网站。

前端 “进化” 到今天,组件化的思想早已深入人心。

组件库的出现更是提高了不少的开发效率。网上对于程序员是否需要重新造轮子一直还是有争论的。

但不管争论如何,该学的东西还是得学。毕竟面试需要,工资重要啊。

纯 CSS,原生 JavaScript,jQuery,Vue,React 实现轮播图, 一篇文章帮你全部搞定_第2张图片
纯 CSS,原生 JavaScript,jQuery,Vue,React 实现轮播图, 一篇文章帮你全部搞定_第3张图片

可以说只要是个组件库,就会有轮播图组件,也有单独做 swpier 的插件。你当然可以选择直接现成的轮子,也可以自己造一个(生活已经很累了,你为什么还要给我增加负担
纯 CSS,原生 JavaScript,jQuery,Vue,React 实现轮播图, 一篇文章帮你全部搞定_第4张图片


纯 CSS

卧槽,CSS 这么牛逼的吗?o( ̄▽ ̄)d,CSS yyds

基础版


<html lang="en">

<head>
  <meta charset="utf-8">
  <title>轮播图title>
  <style>
    * {
      margin: 0;
      padding: 0;
      text-align: none;
    }

    /*设置显示图片的大小,溢出隐藏*/
    .slidershow {
      width: 800px;
      height: 600px;
      overflow: hidden;
    }

    /*居中*/
    .middle {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      /*实现块元素百分比下居中*/
    }

    /*导航 设置绝对位置,弹性布局,按钮位置*/
    .navigaion {
      position: absolute;
      bottom: 5px;
      /*底部距离*/
      left: 50%;
      transform: translateX(-50%);
      display: flex;
    }

    /*设置按钮属性*/
    .bar {
      width: 50px;
      height: 10px;
      border: 2px solid #FFF8DC;
      margin: 0.375rem;
      cursor: pointer;
      transition: 0.4s;
    }

    .bar:hover {
      background-color: #FFF8DC;
    }

    /*隐藏了按钮*/
    input[name="r"] {
      position: absolute;
      visibility: hidden;
    }

    /* 图片部分 */
    .slides {
      width: 1000%;
      height: 100%;
      display: flex;
    }

    .slide {
      width: 10%;
      transition: 1.5s;
    }

    .slide img {
      width: 100%;
      height: 100%;
    }

    /* 绑定按钮 */
    /* radio 标签与 img 相关联 */
    #r1:checked~.s1 {
      margin-left: 0;
    }

    #r2:checked~.s1 {
      margin-left: -10%;
    }

    #r3:checked~.s1 {
      margin-left: -20%;
    }

    #r4:checked~.s1 {
      margin-left: -30%;
    }
  style>

head>

<body>
  <div class="slidershow middle">
    <div class="slides">
      <input type="radio" name="r" id="r1" checked/>
      <input type="radio" name="r" id="r2" />
      <input type="radio" name="r" id="r3" />
      <input type="radio" name="r" id="r4" />

      <div class="slide s1">
        <img src="https://cdn.pixabay.com/photo/2020/09/20/10/08/mountain-5586606__340.jpg" alt="photo" />
      div>

      <div class="slide">
        <img src="https://cdn.pixabay.com/photo/2020/09/11/17/01/landscape-5563684__340.jpg" alt="photo" />
      div>

      <div class="slide">
        <img src="https://cdn.pixabay.com/photo/2020/09/23/15/10/street-5596262__340.jpg" alt="photo" />
      div>

      <div class="slide">
        <img src="https://cdn.pixabay.com/photo/2020/09/24/18/00/man-5599377__340.jpg" alt="photo" />
      div>
    div>

    <div class="navigaion">
      <label for="r1" class="bar">label>
      
      <label for="r2" class="bar">label>
      <label for="r3" class="bar">label>
      <label for="r4" class="bar">label>
    div>
  div>
body>
html>

纯 CSS,原生 JavaScript,jQuery,Vue,React 实现轮播图, 一篇文章帮你全部搞定_第5张图片

进阶版


<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <style>
    * {
      padding: 0;
      margin: 0;
      box-sizing: border-box;
    }

    ul {
      list-style: none;
    }

    img {
      display: block;
      max-width: 100%;
      height: auto;
      background-color: #ededed;
    }

    label {
      display: block;
      cursor: pointer;
    }

    a {
      text-decoration: none;
      color: inherit;
    }

    /* 将 radio 按钮移除至屏幕外 */
    input[type="radio"] {
      position: absolute;
      bottom: 0;
      left: -9999px;
    }

    body {
      color: #fff;
      margin: 20px 0;
      font-family: sans-serif;
    }

    .container {
      max-width: 450px;
      padding: 0 20px;
      margin: 0 auto;
    }


    .slidershow-wrapper {
      position: relative;
    }

    /* 采用网格布局 */
    .slidershow-wrapper .slidershow-list {
      display: grid;
    }

    .slidershow-wrapper .slidershow-list li {
      grid-column: 1;
      grid-row: 1;
      opacity: 0;
      transition: opacity 0.25s;
    }

    /* 箭头样式 */
    .slidershow-wrapper .arrows label::before,
    .slidershow-wrapper .arrows label::after {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      width: 40px;
      height: 40px;
      border-radius: 50%;
      color: #000;
      background-position: center;
      background-repeat: no-repeat;
      background-size: 24px 24px;
      background-color: #fff;
      opacity: 0.5;
      transition: opacity 0.25s;
    }

    .slidershow-wrapper .arrows label::before {
      left: 10px;
    }

    .slidershow-wrapper .arrows label::after {
      right: 10px;
    }

    /* 设置小圆圈 */
    .slidershow-wrapper .dots {
      position: absolute;
      bottom: 10px;
      left: 50%;
      transform: translateX(-50%);
      display: flex;
    }

    .slidershow-wrapper .dots li:not(:last-child) {
      margin-right: 8px;
    }

    .slidershow-wrapper .dots label {
      display: inline-block;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      border: 1px solid #fff;
      transition: background 0.25s;
    }

    .slidershow-wrapper .dots label:hover {
      background: currentColor;
    }

    /* 设置小圆圈 */

    /* 缩略图布局 */
    .thumb-list {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      grid-column-gap: 20px;
      margin-top: 20px;
    }

    .thumb-list label {
      display: grid;
    }

    .thumb-list img,
    .thumb-list .outer {
      grid-column: 1;
      grid-row: 1;
    }

    .thumb-list .outer {
      display: grid;
      place-items: center;
      transition: background 0.25s;
    }

    .thumb-list .inner {
      font-size: 18px;
      opacity: 0;
      transform: translateY(20px);
      transition: all 0.25s;
    }

    /* 缩略图布局 */

    [id="image1"]:checked~.container .slidershow-list li:nth-child(1),
    [id="image2"]:checked~.container .slidershow-list li:nth-child(2),
    [id="image3"]:checked~.container .slidershow-list li:nth-child(3),
    [id^="image"]:checked~.container .arrows [for^="image"]:hover::before,
    [id^="image"]:checked~.container .arrows [for^="image"]:hover::after {
      opacity: 1;
    }

    [id="image1"]:checked~.container .arrows [for="image3"]::before,
    [id="image2"]:checked~.container .arrows [for="image1"]::before,
    [id="image3"]:checked~.container .arrows [for="image2"]::before {
      content: '';
      background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/162656/arrow-prev-slideshow.svg);
    }

    [id="image1"]:checked~.container .arrows [for="image2"]::after,
    [id="image2"]:checked~.container .arrows [for="image3"]::after,
    [id="image3"]:checked~.container .arrows [for="image1"]::after {
      content: '';
      background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/162656/arrow-next-slideshow.svg);
    }

    [id="image1"]:checked~.container .dots [for="image1"],
    [id="image2"]:checked~.container .dots [for="image2"],
    [id="image3"]:checked~.container .dots [for="image3"] {
      background: currentColor;
    }

    [id="image1"]:checked~.container [for="image1"] .outer,
    [id="image2"]:checked~.container [for="image2"] .outer,
    [id="image3"]:checked~.container [for="image3"] .outer {
      background: rgba(0, 0, 0, 0.75);
    }

    [id="image1"]:checked~.container [for="image1"] .inner,
    [id="image2"]:checked~.container [for="image2"] .inner,
    [id="image3"]:checked~.container [for="image3"] .inner {
      opacity: 1;
      transform: none;
    }
  style>
head>

<body>

  
  <input type="radio" id="image1" name="image" checked>
  <input type="radio" id="image2" name="image">
  <input type="radio" id="image3" name="image">

  <div class="container">
    <div class="slidershow-wrapper">
      <ul class="slidershow-list">
        <li>
          <figure>
            <img src="https://cdn.pixabay.com/photo/2020/09/20/10/08/mountain-5586606__340.jpg" alt="">
          figure>
        li>
        <li>
          <figure>
            <img src="https://cdn.pixabay.com/photo/2020/09/11/17/01/landscape-5563684__340.jpg" alt="">
          figure>
        li>
        <li>
          <figure>
            <img src="https://cdn.pixabay.com/photo/2020/09/23/15/10/street-5596262__340.jpg" alt="">
          figure>
        li>
      ul>
      <ul class="arrows">
        <li>
          <label for="image1">label>
        li>
        <li>
          <label for="image2">label>
        li>
        <li>
          <label for="image3">label>
        li>
      ul>
      <ul class="dots">
        <li>
          <label for="image1">label>
        li>
        <li>
          <label for="image2">label>
        li>
        <li>
          <label for="image3">label>
        li>
      ul>
    div>
    <ul class="thumb-list">
      <li>
        <label for="image1">
          <img src="https://cdn.pixabay.com/photo/2020/09/20/10/08/mountain-5586606__340.jpg" alt="">
          <span class="outer">
            <span class="inner"> Caption1 span>
          span>
        label>
      li>
      <li>
        <label for="image2">
          <img src="https://cdn.pixabay.com/photo/2020/09/11/17/01/landscape-5563684__340.jpg" alt="">
          <span class="outer">
            <span class="inner"> Caption2 span>
          span>
        label>
      li>
      <li>
        <label for="image3">
          <img src="https://cdn.pixabay.com/photo/2020/09/23/15/10/street-5596262__340.jpg" alt="">
          <span class="outer">
            <span class="inner">Caption3 span>
          span>
        label>
      li>
    ul>
  div>
body>

html>

小声BB:忘记了代码的原地址,有知道的告诉我一声,我附上


原生 JavaScript


<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=0">
  <title>Documenttitle>
  <style>
    * {
      margin: 0;
      padding: 0;
      touch-action: pan-y;
    }

    html,
    body {
      height: 100%;
      overflow: hidden;
    }

    #wrap {
      height: 100%;
      overflow: hidden;
    }

    .carousel-wrap {
      position: relative;
      overflow: hidden;
    }

    .carousel-wrap>.list {
      list-style: none;
      overflow: hidden;
      position: absolute;
    }

    .carousel-wrap>.list>li>a,
    .carousel-wrap>.list>li>a>img {
      display: block;
    }

    .carousel-wrap>.list>li>a>img {
      width: 100%;
    }

    .carousel-wrap>.list>li {
      float: left;
    }

    .carousel-wrap>.list {
      overflow: hidden;
    }

    .carousel-wrap>.points-wrap {
      position: absolute;
      bottom: 0;
      width: 100%;
      text-align: center;
      z-index: 1;
    }

    .carousel-wrap>.points-wrap>span {
      width: 10px;
      height: 10px;
      border-radius: 50%;
      background-color: #000;
      display: inline-block;
      margin-left: 5px;
    }

    .carousel-wrap>.points-wrap>span.active {
      background-color: #fff;
    }
  style>
head>

<body>
  <div id="wrap">
    <div class="carousel-wrap" needCarousel needAuto>
      <div class="points-wrap">div>
    div>
  div>
  <script>
    (function (w) {
      // w => window
      w.swiper = {}

      w.swiper.css = function css(node, type, val) {
        if (node && typeof node["transform"] === "undefined") {
          node["transform"] = {}
        }
        if (arguments.length >= 3) {
          var text = ""
          node["transform"][type] = val

          for (item in node["transform"]) {
            if (node["transform"].hasOwnProperty(item)) {
              switch (item) {
                case "translateX":
                case "translateY":
                  text += item + "(" + node["transform"][item] + "px)"
                  break;
                case "scale":
                  text += item + "(" + node["transform"][item] + ")"
                  break;
                case "rotate":
                  text += item + "(" + node["transform"][item] + "deg)"
                  break;
              }
            }
          }
          node.style.transform = node.style.webkitTransform = text
        } else if (arguments.length === 2) {
          val = node["transform"][type]
          if (typeof val === "undefined") {
            switch (type) {
              case "translateX":
              case "translateY":
              case "rotate":
                val = 0
              case "scale":
                val = 1
                break;
            }
          }
          return val
        }
      }
      
      w.swiper.carousel = function carousel(arr) {
        // 创建布局
        var carouselWrap = document.querySelector('.carousel-wrap')
        // 
        if (carouselWrap) {
          // 获取图片数组的长度
          var pointslength = arr.length

          // 判断该元素是否需要轮播
          var needCarousel = carouselWrap.getAttribute("needCarousel")
          needCarousel = needCarousel === null ? false : true
          // 连接数组
          if (needCarousel) {
            arr = arr.concat(arr)
          }

          // 创建下方的小圆点
          var ulNode = document.createElement('ul')
          var styleNode = document.createElement('style')
          // ul 添加样式
          ulNode.classList.add('list')
          // 根据 arr 的长度生成 img 标签
          for (let i = 0; i < arr.length; i++) {
            ulNode.innerHTML += `
  • ${arr[i]}" alt="">
  • `
    } // 生成 li 的宽度 styleNode.innerHTML = `.carousel-wrap>.list>li {width: ${1 / arr.length * 100}%;} .carousel-wrap>.list {width: ${arr.length}00%;}` // 加入页面中 carouselWrap.appendChild(ulNode) document.head.appendChild(styleNode) var imgNodes = document.querySelector('.carousel-wrap>.list>li>a>img') // 图片撑满容器 setTimeout(function () { carouselWrap.style.height = imgNodes.offsetHeight + 'px' }, 100) var pointsWrap = document.querySelector('.carousel-wrap > .points-wrap') // 根据小圆点数组的长度,往页面当中插入小圆点。如果是第一个,那默认为选中。 if (pointsWrap) { for (let i = 0; i < pointslength; i++) { if (i === 0) { pointsWrap.innerHTML += `` } else { pointsWrap.innerHTML += `` } } // 小圆点 var pointsSpan = document.querySelectorAll('.carousel-wrap > .points-wrap > span') } // 滑动布局 var index = 0 // 手指的位置 var startX = 0 // 元素的位置 var elementX = 0 var disX = 0 // 监听 touchstart 事件 carouselWrap.addEventListener('touchstart', function (ev) { ev = ev || event var TouchC = ev.changedTouches[0] ulNode.style.transition = 'none' // 无缝逻辑(点击第一组第一张,瞬间调到第二组第一张) // (点击第二组最后一张,瞬间调到第一组最后一张) if (needCarousel) { var index = swiper.css(ulNode, "translateX") / document.documentElement.clientWidth if (-index === 0) { index = -pointslength } else if (-index === (arr.length - 1)) { index = -(pointslength - 1) } swiper.css(ulNode, "translate", index * document.documentElement.clientWidth) } startX = TouchC.clientX // elementX = translateX elementX = swiper.css(ulNode, "translateX") // 清除定时器 clearInterval(timer) }, { passive: false }) // 监听 touchmove 事件 carouselWrap.addEventListener('touchmove', function (ev) { ev = ev || event var TouchC = ev.changedTouches[0] var nowX = TouchC.clientX var disX = nowX - startX swiper.css(ulNode, "translateX", elementX + disX) }, { passive: false }) // 监听 touchend 事件 carouselWrap.addEventListener('touchend', function (ev) { ev = ev || event // index 代表窗口 ul 的实时位置 index = swiper.css(ulNode, "translateX") / document.documentElement.clientWidth index = Math.round(index) // 超出控制 if (index > 0) { index = 0 } else if (index < 1 - arr.length) { index = 1 - arr.length } dots(index) ulNode.style.transition = '1s transform' swiper.css(ulNode, "translateX", index * (document.documentElement.clientWidth)) // 开启自动轮播 if (needAuto) { auto() } }, { passive: false }) var timer = 0 // 抽象图片下标 var needAuto = carouselWrap.getAttribute("needAuto") needAuto = needAuto === null ? false : true // 自动轮播 if (needAuto) { auto() } function auto() { clearInterval(timer) timer = setInterval(function () { if (index === 1 - arr.length) { ulNode.style.transition = "none" index = 1 - arr.length / 2 swiper.css(ulNode, "translateX", index * document.documentElement.clientWidth) } setTimeout(function () { index-- ulNode.style.transition = "1s transform" dots(index) swiper.css(ulNode, "translateX", index * document.documentElement.clientWidth) }, 50) }, 2000) } function dots(index) { if (!pointsWrap) { return } for (var i = 0; i < pointsSpan.length; i++) { pointsSpan[i].classList.remove('active') } pointsSpan[-index % pointslength].classList.add('active') } } } })(window)
    script> <script> window.onload = function () { document.addEventListener('touchstart', function (ev) { ev = ev || event ev.preventDefault() }); let arr = [ 'https://cdn.pixabay.com/photo/2013/07/18/20/26/sea-164989__480.jpg', 'https://cdn.pixabay.com/photo/2013/07/25/01/31/forest-166733__340.jpg', 'https://cdn.pixabay.com/photo/2014/10/07/13/48/mountain-477832__340.jpg', 'https://cdn.pixabay.com/photo/2015/03/28/16/40/lake-696098__340.jpg', 'https://cdn.pixabay.com/photo/2016/10/18/21/22/beach-1751455__340.jpg' ] swiper.carousel(arr) } script> body> html>

    jQuery

    怎么说呢,现在这个 Vue,React, Angular 框架的时代,用 jQuery多少有点看不起这三个框架。

    狗头保命

    
    <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>Documenttitle>
      <script src="./jq.js">script>
      <style>
        a,
        ul,
        li {
          list-style: none;
          text-decoration: none;
          margin: 0;
          padding: 0;
        }
    
        .wrap {
          width: 600px;
          height: 400px;
          margin: 100px auto;
          position: relative;
          overflow: hidden;
        }
    
        .navs {
          width: 4200px;
          height: 100%;
          position: absolute;
          top: 0;
          left: -600px;
        }
    
        .navs li {
          width: 600px;
          height: 100%;
          float: left;
        }
    
        .navs li img {
          width: 100%;
          height: 100%;
        }
    
        #bots {
          display: inline-block;
          width: 600px;
          height: 40px;
          background: rgba(66, 57, 57, 0.3);
          text-align: center;
          position: absolute;
          bottom: 0;
          left: 0;
        }
    
        #bots li {
          width: 15px;
          height: 15px;
          border-radius: 50%;
          background: #fff;
          position: relative;
          left: 220px;
          top: 10px;
          margin-left: 10px;
          float: left;
        }
    
        #bots .active {
          background: #000;
        }
      style>
    head>
    
    <body>
      <div class="wrap" id="box">
        <ul id='navs' class="navs">
          <li><img src="https://cdn.pixabay.com/photo/2016/10/18/21/22/beach-1751455__340.jpg" />li>
          <li><img src="https://cdn.pixabay.com/photo/2013/07/18/20/26/sea-164989__480.jpg" />li>
          <li><img src="https://cdn.pixabay.com/photo/2013/07/25/01/31/forest-166733__340.jpg" />li>
          <li><img src="https://cdn.pixabay.com/photo/2014/10/07/13/48/mountain-477832__340.jpg" />li>
          <li><img src="https://cdn.pixabay.com/photo/2015/03/28/16/40/lake-696098__340.jpg" />li>
          <li><img src="https://cdn.pixabay.com/photo/2016/10/18/21/22/beach-1751455__340.jpg" />li>
          <li><img src="https://cdn.pixabay.com/photo/2013/07/18/20/26/sea-164989__480.jpg" />li>
        ul>
        <ul id="bots">
          <li class="bot active">li>
          <li class="bot">li>
          <li class="bot">li>
          <li class="bot">li>
          <li class="bot">li>
        ul>
      div>
    
      <script>
        // 1.图片不断出现/隐藏  不断向左侧移动
        // 2.对应的小圆点背景颜色变红
        let num = 1;
        let i = 0;
        let timer = null;
        swiper();
        
        // 把定时器功能做一个函数封装
        function swiper() {
          timer = setInterval(() => {
            // 1、图片功能
            num++;
            // 设置条件 当num大于6,num=2
            if (num > 6) {
              // num = 6的时候,其实显示  ban1  
              // 应该通过样式赋值的形式,直接变为 真正的 ban1
              $("#navs").css('left', -600)
              num = 2;
            }
            $("#navs").animate({ left: -num * 600 }, 500);
    
            // 2.小圆点功能
            i++;
            if (i > 4) {
              i = 0;
            }
            $("#bots li").eq(i).addClass('active').siblings().removeClass('active');
          }, 2000);
        }
    
        // 鼠标移入 清除定时器
        $(".wrap").mouseover(() => {
          clearInterval(timer);
        });
    
        // 鼠标移出 开启定时器
        $(".wrap").mouseout(() => {
          swiper();
        });
      script>
    body>
    
    html>
    

    Vue

    实现效果如下

    写之前我们需要安装

    npm install better-scroll

    slider.vue

    <template>
      <div class="slider" ref="slider">
        <div class="slider-group" ref="sliderGroup">
          <slot>
          </slot>
        </div>
        <div class="dots">
          <span
            class="dot"
            v-for="(item, index) in dots"
            :key="index"
            :class="{active: currentPageIndex === index}"
          ></span>
        </div>
      </div>
    </template>
    
    <script>
    import BScroll from 'better-scroll'
    import { addClass } from '../../common/js/dom'
    export default {
      data() {
        return {
          dots: [],
          currentPageIndex: 0
        }
      },
      props: {
        loop: {
          type: Boolean,
          default: true
        },
        autoPlay: {
          type: Boolean,
          default: true
        },
        interval: {
          type: Number,
          default: 4000
        }
      },
      mounted() {
        setTimeout(() => {
          this._setSliderWidth()
          this._initDots()
          this._initSlider()
    
          if (this.autoPlay) {
            this._play()
          }
        }, 20)
    
        window.addEventListener('resize', () => {
          if (!this.slider) {
            return
          }
          this._setSliderWidth(true)
          this.slider.refresh()
        })
      },
      methods: {
        _setSliderWidth(isResize) {
          this.children = this.$refs.sliderGroup.children
          let width = 0
          let slideWidth = this.$refs.slider.clientWidth
          for (let i = 0; i < this.children.length; i++) {
            let children = this.children[i]
    
            addClass(children, 'slider-item')
            children.style.width = slideWidth + 'px'
            width += slideWidth
          }
          if (this.loop && !isResize) {
            width += 2 * slideWidth
          }
          this.$refs.sliderGroup.style.width = width + 'px'
        },
        _initSlider() {
          this.slider = new BScroll(this.$refs.slider, {
            scrollX: true,
            scrollY: false,
            momentum: false,
            snap: true,
            snapLoop: this.loop,
            snapThreshold: 0.3,
            snapSpeed: 400
          })
    
          this.slider.on('scrollEnd', () => {
            let pageIndex = this.slider.getCurrentPage().pageX
            if (this.loop) {
              pageIndex -= 1
            }
            this.currentPageIndex = pageIndex
    
            if (this.autoPlay) {
              clearTimeout(this.timer)
              this._play()
            }
          })
        },
        _initDots() {
          this.dots = new Array(this.children.length)
        },
        _play() {
          let pageIndex = this.currentPageIndex + 1
          if (this.loop) {
            pageIndex += 1
          }
          this.timer = setTimeout(() => {
            this.slider.goToPage(pageIndex, 0, 400)
          }, this.interval)
        }
      },
      destroyed() {
        clearTimeout(this.timer)
      }
    }
    </script>
    
    <style scoped lang="stylus">
      .slider
        min-height: 1px
        .slider-group
          position: relative
          overflow: hidden
          white-space: nowrap
          .slider-item
            float: left
            box-sizing: border-box
            overflow: hidden
            text-align: center
            height 200px
            .a
              display: block
              width: 100%
              overflow: hidden
              text-decoration: none
            img
              display: block
              width: 100%
        .dots
          position: absolute
          right: 0
          left: 0
          bottom: 12px
          text-align: center
          font-size: 0
          .dot
            display: inline-block
            margin: 0 4px
            width: 8px
            height: 8px
            border-radius: 50%
            background: rgba(255, 255, 255, 0.5)
            &.active
              width: 20px
              border-radius: 5px
              background: rgba(255, 255, 255, 0.8)
    </style>
    

    dom.js

    export function addClass(el, className) {
      if (hasClass(el, className)) {
        return
      }
      let newClass = el.className.split(' ')
      newClass.push(className)
      el.className = newClass.join(' ')
    }
    
    export function hasClass(el, className) {
      let reg = new RegExp('(^|\\s)' + className + '(\\s|$)')
      return reg.test(el.className)
    }
    
    export function getData(el, name, val) {
      const prefix = 'data-'
      name = prefix + name
      if (val) {
        return el.setAttribute(name, val)
      } else {
        return el.getAttribute(name)
      }
    }
    

    使用方法

    <div v-if="recommends.length" class="slider-wrapper">
      <Slider>
        <div v-for="item in recommends" :key="item.linkUrl">
          <router-link :to="item.linkUrl" class="a">
            <img 
            	@load="loadImage" 
            	v-lazy="item.picUrl"  
            	width="100%" 
            	height="200"
            >
          </router-link>
        </div>
      </Slider>
    </div>
    
    import Slider from '../../base/slider/slider'
    data() {
      return {
        recommends: [
          {
            "picUrl": "https://cdn.pixabay.com/photo/2020/08/11/13/28/flowers-5479950__340.jpg",
            "linkUrl": '/'
          },
          {
            "picUrl": "https://cdn.pixabay.com/photo/2020/08/08/20/19/wave-5473869__340.jpg",
            "linkUrl": '/a'
          },
          {
            "picUrl": "https://cdn.pixabay.com/photo/2020/07/05/12/53/rainbow-5372892__340.jpg",
            "linkUrl": '/b'
          }
        ]
      }
    },
    components: {
      Slider
    },
    methods: {
      loadImage() {
        if (!this.checkloaded) {
          this.checkloaded = true
          this.$refs.scroll.refresh()
        }
      }
    }
    style
    
    .slider-wrapper
      position: relative
      width: 100%
      overflow: hidden
      height 200px
    

    React

    最开始传入图片数据

    import Banner from './banner'
    
    let imgUrl = [
      'https://img.zcool.cn/community/010c815e25a8c4a801216518dcc1d4.jpg@1280w_1l_2o_100sh.jpg', 'https://img.zcool.cn/community/0189905e25a8c6a80120a89533cc7f.jpg@1280w_1l_2o_100sh.jpg', 'https://img.zcool.cn/community/01747f5e25a8c9a801216518193452.jpg@1280w_1l_2o_100sh.jpg', 'https://img.zcool.cn/community/01cbba5e25a8cea80120a895743281.jpg@1280w_1l_2o_100sh.jpg', 'https://img.zcool.cn/community/0186025e25a8d3a80121651827af9c.jpg@1280w_1l_2o_100sh.jpg'
    ]
    
    function App() {
      return (
        <div>
          <Banner
            imgUrl={imgUrl}
          />
        </div>
      );
    }
    
    export default App;
    

    基础架构:中间展示图片,两边箭头,下面依据图片数量生成的小圆点

    import React from "react"
    import "./banner.css"
    
    export default class Banner extends React.Component {
    
      render() {
        return (
          <div
            className="container"
          >
            <div className="swiper-box">
              {
                this.props.imgUrl.map((item, index) => {
                  return (
                    <div className="swiper-item" key={index}>
                      <img src={item} alt="" />
                    </div>
                  )
                })
              }
            </div>
    
            <div className="swiper-arrow">
              <div className="arrowLeft iconfont iconqianjin1"></div>
              <div className="arrowRight iconfont iconqianjin"></div>
            </div>
    
            <div className="focus">
              {
                this.props.imgUrl.map((item, index) => {
                  return (
                    <div></div>
                  )
                })
              }
            </div>
          </div>
        )
      }
    }
    

    咦咦咦咦~~~~,so ugly

    为实现无缝衔接轮播,我们需要重新去生成一份数组。props 中解构出 imgUrl

    constructor(props) {
      super(props)
      let { imgUrl } = this.props
      let imgUrlClone = []
      imgUrlClone = imgUrlClone.concat([], imgUrl)
      imgUrlClone.push(imgUrl[0])
      imgUrlClone.unshift(imgUrl[imgUrl.length - 1])
      console.log(imgUrlClone)
    }
    

    一顿操作下来,假设 imgUrl = [A, B, C, D, E] => imgUrlClone = [E, A, B, C, D, E, A]

    {
      this.imgUrlClone.map((item, index) => {
        return (
          <div className="swiper-item" key={index}>
            <img src={item} alt="" />
          </div>
        )
      })
    }
    


    接下来,要将图片的显示变为正常样式

    let { width, height, step, speed } = this.state;
    
    let swiperBoxStyle = {
      width: `${this.imgUrlClone.length * width}px`,
      left: `${-step * width}px`,
      height: height + "px",
      transition: `all ${speed}ms linear`
    }
    let commom = {
      width: width + "px",
      height: height + "px"
    }
    

    分别加到 className="container"className="swiper-box" 上。

    静态布局结束之后,让我们的图片动起来。

    this.state = { speed, step, width, height }
    
    componentDidMount() {
      if (this.props.autoplay) {
        this.timer = setInterval(() => {
          this.next()
        }, this.props.interval);
      }
    }
    
    next = () => {
      let { step } = this.state
      if (step >= this.imgUrlClone.length - 1) {
        this.setState({
          step: 1,
          speed: 0
        })
      }
      setTimeout(() => {
        this.setState({
          step: this.state.step + 1,
          speed: this.props.speed
        })
      }, 0)
    }
    

    切换小圆点对应的 active 样式

    <div className="focus">
      {
        this.props.imgUrl.map((item, index) => {
          if (step === this.imgUrlClone.length - 1) {
            step = 1
          }
          if (step === 0) {
            step = this.imgUrlClone.length - 2
          }
          return (
            <div className={index + 1 === step ? "active" : ""} key={index}></div>
          )
        })
      }
    </div>
    

    为左右箭头添加事件

    <div className="swiper-arrow">
      <div className="arrowLeft iconfont iconqianjin1" onClick={this.prev}>div>
      <div className="arrowRight iconfont iconqianjin" onClick={this.next}>div>
    div>
    
    prev = () => {
      let { step } = this.state
      if (step <= 0) {
        this.setState({
          step: this.imgUrlClone.length - 2,
          speed: 0
        })
      }
      setTimeout(() => {
        this.setState({
          step: this.state.step - 1,
          speed: this.props.speed
        })
      }, 0)
    }
    

    锦上添花,鼠标移入,轮播停止。鼠标移出,轮播继续

    <div
      className="container"
      style={commom}
      onMouseEnter={this.removeInte}
      onMouseLeave={this.addInter}
    >div>
    
    removeInte = () => {
      clearInterval(this.timer)
    }
    addInter = () => {
      if (!this.props.autoplay) return
      this.timer = setInterval(() => {
        this.next()
      }, this.props.interval);
    }
    

    源代码:React 轮播图组件

    你可能感兴趣的:(JavaScript,CSS,javascript,css,vue.js,reactjs,jQuery)