JS图片无缝轮播实现

2,332 阅读4分钟

轮播说明

最近做的项目中,用到了很多轮播特效,找了几款插件都不满足需求,并且项目中的轮播样式太多,用插件也不现实,决定自己手动实现。

轮播的核心思想就是在图片列表首尾两端插入图片,利用视觉差,用户看不到位置改变,实现无缝轮播。

例如,用户点击到最后一张图片的时候,动画会先移动到添加的第一张图片上,然后利用回调函数,把真正的第一张图片转移到视觉窗口上。

轮播实现步骤

    1. 把要实现的轮播图片包到<ul>下的<li>中,并把<ul>的width设置很多,可以是1000%,要放得下所有<li>,不能换行。
    1. 设置轮播图片的宽度,可以是固定的,也可以根据父级窗口来动态设定。
    1. 克隆首尾两个图片节点插入到尾首,实现无缝轮播。
    1. 如果需要点播的话,还需要动态生成点播按钮。
    1. 设置图片序号标识符,向前向后及点播都需要通过该标识符来控制。
    1. 向前向后及点播处理函数中,移动<ul>的偏移量left即可,需要注意首尾的处理过程,先移动到克隆的图片上,在利用回调移动到真正的图片上。此外如果有文本需要改变。

示例代码

html代码如下:

<div class="art container">
  <div class="row">
    <div class="col-md-5">
      <div class="art_left">
        <div class="introduce_title">
          <h3 class="title_space">黄鹤楼参观简介</h3>
          <p class="title_en">SIGHSEEING INTRODUCING TO YELLOW CRANE TOWER</p>
          <hr>
          <p id="sub_title">黄鹤楼五楼</p>
        </div>
        <p class="introduce_detail">
          黄鹤楼位于湖北省武汉市长江南岸的武昌蛇山之巅,濒临万里长江,是国家5A级旅游景区,“江南三大名楼”之一,自古享有“天下江山第一楼“和”天下绝景“之称。黄鹤楼是武汉市标志性建筑,与晴川阁、古琴台并称“武汉三大名胜”。黄鹤楼坐落在海拔61.7米的蛇山顶,以清代“同治楼”为原型设计,京广铁路的列车从楼下呼啸而过。楼高5层,总高度51.4米,建筑面积3219平方米。黄鹤楼内部由72根圆柱支撑,外部有60个翘角向外伸展,屋面用10多万块黄色琉璃瓦覆盖构建而成。
        </p>
      </div>
    </div>
    <div class="col-md-7">
      <div class="art_right">
        <!--轮播图-->
        <ul>
          <li><a href="#"><img src="./public/images/main/art/test.png" alt=""></a></li>
          <li><a href="#"><img src="./public/images/main/art/picture.png" alt=""></a></li>
          <li><a href="#"><img src="./public/images/main/art/test2.png" alt=""></a></li>
          <li><a href="#"><img src="./public/images/main/art/test3.png" alt=""></a></li>
          <li><a href="#"><img src="./public/images/main/art/test4.png" alt=""></a></li>
        </ul>
        <ol class="bar">
          <!-- 小按钮数量无法确定,由js动态生成 -->
        </ol>
        <!--左右焦点-->
        <div id="arrow">
          <img src="./public/images/main/art/left.png" alt="" id="left">
          <img src="./public/images/main/art/right.png" alt="" id="right">
        </div>
      </div>
    </div>
  </div>
</div>

部分css代码如下:

/* 包含ul的父级元素 */
.art_right {
  width: 100%;
  /* 下面三个属性是必须的,高度以及定位溢出隐藏 */
  height: 450px;
  overflow: hidden;
  position: relative;
}

.art_right ul {
  /* ul宽度设为很大,可以包含所有li元素 */
  width: 1000%;
  /* 相对定位,通过left来控制图片轮播位置 */
  position: absolute;
  list-style: none;
  left: 0;
  top: 0;
  padding: 0;
}

.art_right ul li {
  /* li元素设为左浮动,使其显示在横向一行中 */
  float: left;
}

.art_right ul img {
  /* mix-width: 620px; */
  height: 450px;
}

#left {
  position: absolute;
  top: 45%;
  left: 5px;
}

#right {
  position: absolute;
  top: 45%;
  right: 5px;
}

.art_right ol {
  position: absolute;
  left: 25%;
  bottom: 0;
  text-align: center;
  margin: 0;
  padding: 0;
}

.art_right ol li{
  display: inline-block;
  width: 40px;
  height: 35px;
  background: url(../images/main/art/choice-two.png) no-repeat center center;
  margin: 15px;
  cursor: pointer;
  background-size: contain;
}
.current{
  background: url(../images/main/art/choice-one.png) !important; 
}

js代码如下:

$(function () {
  var img_box = $(".art_right > ul");
  var imgList = $(".art_right > ul > li");
  var dotList = $(".art_right > .bar");
  var imgLen = imgList.length;
  //获取到播放窗口大小
  var imgWidth = $(".art_right")[0].offsetWidth;
  $(img_box).css({ left: -imgWidth + "px" });
  $(".art_right > ul > li img").each(function (index, elemnt) {
    $(elemnt).css({ width: imgWidth + "px" });
  });
  
  //设置序号标记
  var flag = 0;

  //生成点播的按钮
  for (var i = 0; i < imgLen; i++) {
    dotList.append("<li index="+i+"></li>");
  }

  //需要在头尾生成连续播放需要的节点,轮播的重点
  var first_img = $(imgList[0]).clone();
  var last_img = $(imgList[imgLen - 1]).clone();
  $(img_box)[0].append(first_img[0]);
  $(img_box)[0].prepend(last_img[0]);

  //默认第一张图片是选中状态
  $(($(".bar").children())[0]).addClass("current");

  //点击向后播放
  $("#right").click(function (e) {
    e.preventDefault();
    flag++;
    //flag从0的值加1之后,flag的值是1,然后ul移动出去一个图片
    //如果flag==5说明,此时显示第6个图(内容是第一张图片),第一个小按钮有颜色,
    if (flag == imgLen) {
      //第五个按钮颜色去掉
      $(($(".bar").children())[imgLen - 1]).removeClass("current");
      //第一个按钮颜色设置上
      $(($(".bar").children())[0]).addClass("current");
      $(img_box).animate({ 'left': -(flag + 1) * imgWidth + "px" }, 1000, function () {
        $(img_box).css({ 'left': -imgWidth + "px" });
      });
      flag = 0;
    } else {
      //去掉所有的小按钮的背景颜色
      for (var i = 0; i < imgLen; i++) {
        $(($(".bar").children())[i]).removeClass("current");
      }
      $(($(".bar").children())[flag]).addClass("current");
      var w = -(flag + 1) * imgWidth;
      $(img_box).animate({ 'left': w + "px" }, 1000);
    }
  });
  
  $("#left").click(function(e){
    e.preventDefault();
    flag--;
    if (flag == -1) {
      $(($(".bar").children())[0]).removeClass("current");
      $(($(".bar").children())[imgLen - 1]).addClass("current");
      $(img_box).animate({ 'left': "0" }, 1000, function () {
        $(img_box).css({ 'left': -imgLen * imgWidth + "px" });
      });
      flag = imgLen - 1;
    }else{
      //去掉所有的小按钮的背景颜色
      for (var i = 0; i < imgLen; i++) {
        $(($(".bar").children())[i]).removeClass("current");
      }
      $(($(".bar").children())[flag]).addClass("current");
      var w = -(flag + 1) * imgWidth;
      $(img_box).animate({ 'left': w + "px" }, 1000);
    }
  });

  $(".bar > li").click(function(e){
    e.preventDefault();
    var index = this.getAttribute('index');
    flag = parseInt(index);
    for (var i = 0; i < imgLen; i++) {
      $(($(".bar").children())[i]).removeClass("current");
    }
    $(($(".bar").children())[flag]).addClass("current");
    var w = -(flag + 1) * imgWidth;
    $(img_box).animate({ 'left': w + "px" }, 1000);
    //举例轮播时文本可以更改
    $("#sub_title").text(flag+1);
  });
});

最后实现效果: