Web前端之轮播图的写法

全文思维导图如下:

轮播图

一.实现效果

1.最终视觉图:

2.效果功能:

  • 鼠标不进入时隐藏左右箭头且自动播放
  • 可通过圆圈点击切图,或箭头切图
  • 可循环,且连续点击会等一张播放完才切图

二.实现原理

1.主要构成部分

  • 多张图片【放在ul下的小 li 里面】
  • 左右箭头【使用arrow-r,arrow-l 类,里面放小图标】
  • 索引圆圈【放在ol下的小li里面,且动态生成】

2.涉及知识点(随附代码)

图片循环播放原理

克隆第一张图片【深克隆,使用cloneNode(ture)方法】,从而最后一张播放完后下一张又会是第一张,同时,当走到了最后一张时,将ul的位置跳到最左;同理,走到第一张时,跳到最右,从而悄无声息地实现 "伪循环"。

缓动动画

  • 实现原理

可传参数三个分别是 obj, target, callback ,第一个表示动画作用对象,第二个表示要移动的目标位置,第三个表示移动后的回调函数。

首先是计算移动步长,此处是以目标位置减去当前对象距左边的距离,然后除以10,随着当前对象距左边距离越来越接近目标位置,步长会越来越短,从而实现 缓动效果

然后每次移动都让当前对象的左距变为 当前左距+步长 即可实现 移动。

  • 注意事项

(1)求步长(step)时,注意根据其正负来决定取整时是取大(ceil)还是取小(floor)

(2)在移动过程中,注意对象左距的改变(通过obj.style.left)最后要加单位 'px'

(3)此处封装的动画函数是针对左右移动的,如果要上下移动,只需更改为上距即可

  • 具体代码
// 封装缓动动画效果函数
function animate(obj, target, callback) {
  clearInterval(obj.timer);
  //设置计时器
  obj.timer = setInterval(function () {
    // 步长值写到定时器的里面
    var step = (target - obj.offsetLeft) / 10;
    // 对步长进行取整,以防止出现小数问题,
    // 并考虑到后退时会产生正负,取整时要考虑是取大还是取小
    step = step > 0 ? Math.ceil(step) : Math.floor(step);
    //ceil [天花板] 、floor [地板]
    if (obj.offsetLeft == target) {
      clearInterval(obj.timer);
      //回调函数写到计时器结束里面
      // if (callback) {
      //     //如果有函数实参传进来,就调用函数
      //     callback();
      // }
      // 上面两行有更高级的写法,即使用或与运算符,如下:
      callback && callback();
    } else {
      obj.style.left = obj.offsetLeft + step + 'px';
    }
  }, 30)
}

计时器

代码见上animate函数,此处使用的setInterval(function, time),传入参数分别是执行函数和执行间隔时间,该计时器将会每间隔time时间执行一次function函数;

在animate.js中每次都先clearInterval,是为了保证动画被反复执行时(如多次点击箭头)都会先删除上一次生成的计时器,防止计时器的叠加;

且为保证每一个对象有自己独有的计时器,所以自定义了timer属性,将obj.timer = setInterval(){} ,就可以保证多个对象不会共用一个计时器。

圆圈效果

结构:在圆角矩形(ol)中放置圆圈(小 li )

特点:小圆圈是动态添加的,使用js判断图片张数创建节点,然后添加到矩形中

注意:因为考虑到后续图片的移动,所以要在创建节点时就给li添加一个自定义的属性用于索引(自定义属性名用data-开头)

(使用这行代码增加属性用来索引 var index = this.getAttribute('data-index');)

以下是圆角矩形(类名为.circle)的CSS代码实现:

.main .circle {
            display: inline-block;
            position: absolute;
            /*下面三行用来定位和居中*/
            left: 50%;
            bottom: 10px;
            transform: translateX(-50%);
            /*下面三行分别用来调色、形状和上下居中*/
            background-color: rgba(100, 100, 100, 0.5);
            border-radius: 7px;
            font-size: 0;
        }

以下是内部小圆圈的CSS代码实现【.current类是当前显示图片】

.circle li {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #fff;
  margin: 2px;
}

ol .current{
  background-color: skyblue;
        }

显示图标

此处使用的是阿里图标,点击右边可跳转 iconfont-阿里巴巴矢量图标库,使用方法之一

步骤如下:

①下载并引入font文件夹(解压后内容如下)

②引入到html中,

<link rel="stylesheet" href="../font_icon/iconfont.css">

③直接使用类名引入图标,注意要引入两个!一个是iconfont,一个是icon-icon-xxx【到iconfont.css里面找】

<a href="javascript:;" class="arrow-l iconfont icon-icon-arrow-left"></a>

节流阀(补充)

使用一个flag标志即可,放在回调函数中,变换数值

三.具体代码

1.html页面

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>网页轮播图</title>
    <link rel="stylesheet" href="../font_icon/iconfont.css">
    <script src="animate.js"></script>
    <script src="lbt.js"></script>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      
      li {
        float: left;
        list-style: none;
      }
      
      a {
        /*取消链接的下划线*/
        text-decoration: none;
      }
      
      .main {
        position: relative;
        height: 250px;
        width: 400px;
        /*text-align: center;*/
        margin: 160px auto;
        /*background-color: skyblue;*/
        overflow: hidden;
      }
      
      .main ul {
        position: absolute;
        height: 100%;
        width: 4000px;
      }
      
      /*
      可以让小li浮动,来让图片横排
      但是也要调整ul的宽度,否则装不下去
      */
      
      img {
        width: 400px;
        height: 250px;
      }
      
      /*可以实现代码的复用*/
      .arrow-r, .arrow-l {
        display: none;
        
        position: absolute;
        right: 0;
        top: 50%;
        margin-top: -20px;
        
        width: 24px;
        height: 40px;
        line-height: 40px;
        
        text-align: center;
        color: #fff;
        font-size: 18px;
        
        background: rgba(0, 0, 0, .3);
        
        /*因为对ul使用了positon定位,所以存在覆盖优先级问题*/
        z-index: 2;
      }
      
      .arrow-r:hover{
        color: lightcoral;
      }
      .arrow-l:hover{
        color: lightcoral;
      }
      
      .arrow-l {
        left: 0;
      }
      
      .main .circle {
        display: inline-block;
        position: absolute;
        /*下面三行用来定位和居中*/
        left: 50%;
        bottom: 10px;
        transform: translateX(-50%);
        /*下面三行分别用来调色、形状和上下居中*/
        background-color: rgba(100, 100, 100, 0.5);
        border-radius: 7px;
        font-size: 0;
      }
      
      .circle li {
        display: inline-block;
        width: 10px;
        height: 10px;
        border-radius: 50%;
        background: #fff;
        margin: 2px;
      }
      
      ol .current{
        background-color: skyblue;
      }
    </style>
  </head>
  <body>
    <div class="main">
      <!--    左侧箭头-->
      <!--    类中应包括iconfont 和 标识类-->
      <a href="javascript:;" class="arrow-l iconfont icon-icon-arrow-left"></a>
      <!--    右侧箭头-->
      <a href="javascript:;" class="arrow-r iconfont icon-icon-arrow-right"></a>
      <!--    轮播图-->
      <ul>
        <li>
          <a href="#"><img src="../images/1.jpg" alt=""></a>
        </li>
        <li>
          <a href="#"><img src="../images/2.jpg" alt=""></a>
        </li>
        <li>
          <a href="#"><img src="../images/3.jpg" alt=""></a>
        </li>
        <li>
          <a href="#"><img src="../images/4.jpg" alt=""></a>
        </li>
      </ul>
      <!--    小圆圈-->
      <ol class="circle">
      </ol>
    </div>
  </body>
</html>

2.轮播图js

window.onload = function () {
  // 1。获取元素
  var arrow_l = document.querySelector('.arrow-l');
  var arrow_r = document.querySelector('.arrow-r');
  var focus = document.querySelector('.main');
  //因为ul可能有很多,所以应该查找focus下的ul
  var ul = focus.querySelector('ul');
  var ol = focus.querySelector('ol');
  
  var num = 0;//用于作为图片索引的
  // var circle = 0;//用于作为圆圈索引的,此处我用num兼容了该作用
  
  // 2.鼠标经过就显示左右箭头并停止自动播放
  focus.addEventListener('mouseenter', function () {
    arrow_l.style.display = 'block';
    arrow_r.style.display = 'block';
    clearInterval(timer);
    timer = null;
  })
  //鼠标离开就开启自动播放
  focus.addEventListener('mouseleave', function () {
    arrow_l.style.display = 'none';
    arrow_r.style.display = 'none';
    timer = setInterval(function (){
      arrow_r.click();
    },3000);
  })
  
  // 3.根据ul下的小li的个数来生成小圆圈
  for (var i = 0; i < ul.children.length; i++) {
    var li = document.createElement('li');
    // 为每个小li添加属性,设置索引号
    li.setAttribute('data-index', i);
    // 4.在生成小li时就给它绑定单击事件
    li.addEventListener('click', function () {
      var index = this.getAttribute('data-index');
      
      num = index;//此处将index的值赋给num,实现箭头点击和小圆圈的同步
      
      var target = -focus.offsetWidth * index;
      // console.log(index);
      // console.log(target);
      // 5.利用排他思想,突出被选中的小圆圈
      for (var j = 0; j < ol.children.length; j++) {
        //取消其他圆圈之前点击时加上的类名
        ol.children[j].className = '';
      }
      this.className = 'current';
      animate(ul, target);
    })
    //把li插入到ol中
    ol.appendChild(li);
  }
  ol.children[0].className = 'current';
  // 6.克隆第一张图片(li)放到ul最后面(放在循环外就不会生成多余的小圆圈)
  var first = ul.children[0].cloneNode(true);//true表示深克隆(不仅克隆节点,还克隆内容)
  ul.appendChild(first);//将克隆的图片加到ul中
  // 7.点击右侧按钮,图片滚动一张
  
  //设置一个变量作为节流阀,用于控制点击箭头不要滚动过快
  var flag = true;
  
  arrow_r.addEventListener('click', function () {
    if (flag){
      flag = false; //关闭节流阀
      // 如果走到了最后一张图片,则将ul快速回到第一张
      if (num == ul.children.length - 1) {
        console.log(num);
        ul.style.left = 0;
        num = 0;
      }
      // 此处不能使用else,否则num的值对不上
      num++;
      animate(ul, -focus.offsetWidth * num,function (){
        flag = true; //动画执行完就打开节流阀
      });
      circlechange(num);
    }
  })
  
  //8.点击左侧按钮,同上理
  arrow_l.addEventListener('click', function () {
    if (flag){
      flag = false;
      // 如果走到了第一张图片,则将ul快速回到最后一张
      if (num == 0) {
        num = ul.children.length - 1;
        //注意!一定要在最后加'px'
        ul.style.left = - num * focus.offsetWidth + 'px';
      }
      // 此处不能使用else,否则num的值对不上
      num--;
      animate(ul, -focus.offsetWidth * num,function (){
        flag = true;
      });
      circlechange(num);
    }
  })
  
  //这段改变圆圈的代码是可以复用的
  function circlechange(num){
    // 清除其他小圆圈
    for (var i = 0; i < ol.children.length; i++) {
      ol.children[i].className = '';
    }
    // 将自己此时的小圆圈变色
    if (num == ol.children.length) {
      // 此时num = 4,表示第五张图片
      ol.children[0].className = 'current';
    } else {
      ol.children[num].className = 'current';
    }
  }
  
  //9.自动播放功能(当鼠标移动在上面就停止自动播放)
  var timer = setInterval(function (){
    //arrow_r.click()可以实现自动点击
    arrow_r.click();
  },3000);
  
}

3.缓动动画js

// 封装缓动动画效果函数
function animate(obj, target, callback) {
    clearInterval(obj.timer);
    //设置计时器
    obj.timer = setInterval(function () {
        // 步长值写到定时器的里面
        var step = (target - obj.offsetLeft) / 10;
        // 对步长进行取整,以防止出现小数问题,
        // 并考虑到后退时会产生正负,取整时要考虑是取大还是取小
        step = step > 0 ? Math.ceil(step) : Math.floor(step);
        //ceil [天花板] 、floor [地板]
        if (obj.offsetLeft == target) {
            clearInterval(obj.timer);
            //回调函数写到计时器结束里面
            // if (callback) {
            //     //如果有函数实参传进来,就调用函数
            //     callback();
            // }
            // 上面两行有更高级的写法,即使用或与运算符,如下:
            callback && callback();
        } else {
            obj.style.left = obj.offsetLeft + step + 'px';
        }
    }, 30)
}

  • 9
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值