轮播图

91 阅读1分钟

纯JS实现

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title></title>
  <style type="text/css">
    * {
      margin: 0;
      padding: 0;
    }

    #outer {
      width: 520px;
      height: 333px;
      margin: 50px auto;
      background-color: greenyellow;
      padding: 10px 0px;
      position: relative;
      overflow: hidden;
    }

    #imgList {
      list-style: none;
      position: absolute;
      left: 0px;
    }

    #imgList li {
      float: left;
      margin: 0px 10px;
    }

    #nav {
      position: absolute;
      bottom: 20px;
    }

    #nav a {
      float: left;
      width: 15px;
      height: 15px;
      background-color: red;
      margin: 0 5px;
      opacity: 0.5;
      filter: alpha(opacity=50);
    }

    #nav a:hover {
      background-color: black;
    }
  </style>

  <script type="text/javascript" src="js/tools.js"></script>
  <script type="text/javascript">
    window.onload = function () {
      var timer;
      var imgList = document.getElementById("imgList");
      var imgArr = document.getElementsByTagName("img");
      imgList.style.width = 520 * imgArr.length + "px";
      var outer = document.getElementById("outer");
      var nav = document.getElementById("nav");
      nav.style.left = (outer.offsetWidth - nav.offsetWidth) / 2 + "px";
      var aArr = document.getElementsByTagName("a");
      var num = 0;
      setA();
      for (var i = 0; i < aArr.length; i++) {
        aArr[i].index = i;

        aArr[i].onclick = function () {
          clearInterval(timer);
          num = this.index;
          setA();
          move(imgList, "left", -520 * num, 20, function () {
            autoChange();
          });

        };
      }
      autoChange();
      function setA() {
        if (num == imgArr.length - 1) {
          num = 0;
          imgList.style.left = 0;
        }
        for (var i = 0; i < aArr.length; i++) {
          aArr[i].style.backgroundColor = "";
        }
        aArr[num].style.backgroundColor = "black";
      }
      function autoChange() {
        timer = setInterval(function () {
          num++;
          if (num >= imgArr.length) {
            num = 0;
            imgList.style.left = 0;
          }
          move(imgList, "left", -520 * num, 20, function () {
            setA();
          });
        }, 3000);
      }
    };
  </script>
</head>

<body>
  <div id="outer">
    <ul id="imgList">
      <li><img src="img/1.jpg" alt="冰棍" /></li>
      <li><img src="img/2.jpg" alt="冰棍" /></li>
      <li><img src="img/3.jpg" alt="冰棍" /></li>
      <li><img src="img/4.jpg" alt="冰棍" /></li>
      <li><img src="img/5.jpg" alt="冰棍" /></li>
      <li><img src="img/1.jpg" alt="冰棍" /></li>
    </ul>
    <div id="nav">
      <a href="javascript:;"></a>
      <a href="javascript:;"></a>
      <a href="javascript:;"></a>
      <a href="javascript:;"></a>
      <a href="javascript:;"></a>
    </div>
  </div>

</body>

</html>

tools.js文件

/*
 * 可以用来获取任意的样式
 */
function getStyle(obj, name) {

	return window.getComputedStyle && getComputedStyle(obj, null)[name] || obj.currentStyle[name];
}

/*
 * 提取出一个函数,可以处理一些简单的动画效果
 * 参数:
 * 		obj: 要执行动画的元素
 * 		attr: 执行动画是要修改的属性
 * 		target: 执行动画的目标位置
 * 		speed: 执行动画的速度
 * 		callback: 回调函数,这个函数将会在动画执行完毕之后被调用
 */
function move(obj, attr, target, speed, callback) {
	//开启定时器前,关闭上一个
	/*
	 * 这里我们的timer是一个全局变量,所有的动画执行时,都会共享同一个timer
	 * 	这样将会导致我们执行box2的动画时,会使box1的动画也立即终止
	 * 	所以我们定时器的标识不能作为全局变量保存,而应该保存到要执行动画的对象上
	 */
	clearInterval(obj.timer);

	//获取当前值,动画执行的起始位置
	var current = parseInt(getStyle(obj, attr));
	//起始位置   大于  目标位置 speed为负
	//起始位置  小于 目标位置 speed为正
	if(current > target) {
		//此时speed应该是负数
		speed = -speed;
	}

	//开启一个定时器,用来移动box1
	obj.timer = setInterval(function() {
		//获取box1的left属性值
		var oldValue = parseInt(getStyle(obj, attr));
		//修改值
		var newValue = oldValue + speed;
		//如果newValue大于800
		//如果向右移动,则newValue > target  speed为正
		//如果向左移动,则newValue < target  speed为负
		if(speed > 0 && newValue > target || speed < 0 && newValue < target) {
			newValue = target
		}
		//将其赋值给box1
		obj.style[attr] = newValue + "px";
		//当运行800px时,停止执行动画
		if(newValue == target) {
			clearInterval(obj.timer);
			//动画执行完毕,调用回调函数
			callback && callback();

		}

	}, 30);
}

/*
 * 定义一个函数,专门用来为一个元素添加class属性值
 * 参数
 * 	obj 要添加class属性的元素
 * 	cn 要添加的class的值
 * 	
 */
function addClass(obj, cn) {

	//判断obj中是否含有cn这个class
	if(!hasClass(obj, cn)) {
		obj.className += " " + cn;
	}

}

/*
 * 判断一个对象中是否含有指定的class属性
 * 	参数:
 * 		obj:要检查的对象
 * 		cn:要检查class值
 * 如果对象中具有该class则返回true,否则返回false
 */
function hasClass(obj, cn) {

	//检查obj中是否与b2这个class
	//var reg = /\bb2\b/;
	var reg = new RegExp("\\b" + cn + "\\b");

	return reg.test(obj.className);

}

/*
 * 删除一个元素中的class
 */
function removeClass(obj, cn) {

	//创建一个正则表达式
	var reg = new RegExp("\\b" + cn + "\\b");

	//将class属性中符合正则表达式的内容,替换为空串
	obj.className = obj.className.replace(reg, "");

}

/*
 * 切换一个元素的class属性值
 * 	如果有,则删除
 * 	如果没有,则添加
 */
function toggleClass(obj, cn) {
	//判断obj中是否有cn
	if(hasClass(obj, cn)) {
		//如果有,则删除
		removeClass(obj, cn);
	} else {
		//如果没有,则添加
		addClass(obj, cn);
	}
}

Vue3+TS实现

<template>
      <div class="slideshowBox">
        <div class="box">
          <div class="slideshow" ref="slideshow">
            <img v-for="(item, index) in slideshowData" :key="index" :src="item.slideshowImg">
          </div>
        </div>
        <div class="slideshowSelect">
          <img v-for="(item, index) in slideshowData" :key="index" :src="item.slideshowImg"
            @click="slideshowSelectClick(index)" ref="slideshowSelectImg" :class="{ 'border': index == 0 }" />
        </div>
      </div>
</template>

<script lang="ts">
import { ref, reactive, defineComponent, onMounted } from 'vue';
import move from '@/utils/slideshow'; //轮播工具
export default defineComponent({
  name: 'App',
  setup() {
    // 轮播数据
    let slideshowData = reactive([
      {
        slideshowImg: require('@/assets/image/home/slideshow1_1.jpg'),
      },
      {
        slideshowImg: require('@/assets/image/home/slideshow1_2.jpg'),
      },
      {
        slideshowImg: require('@/assets/image/home/slideshow1_3.jpg'),
      },
      {
        slideshowImg: require('@/assets/image/home/slideshow1_4.jpg'),
      },
      {
        slideshowImg: require('@/assets/image/home/slideshow1_5.jpg'),
      },
      {
        slideshowImg: require('@/assets/image/home/slideshow1_1.jpg'),
      }
    ])
    // 获取轮播ref
    let slideshow = ref()
    let slideshowSelectImg = ref()
    let ind: number = 0;
    let timer: any;
    // 轮播下方选择
    function allDot() {
      if (ind == slideshowData.length - 1) {
        ind = 0;
        slideshow.value.style.left = 0;
      }
      for (var i = 0; i < slideshowSelectImg.value.length; i++) {
        slideshowSelectImg.value[i].classList.remove("border");
      }
      slideshowSelectImg.value[ind].classList.add("border");
    }
    // 无限循环轮播图
    function loopSlideshow() {
      timer = setInterval(function () {
        ind++;
        if (ind >= slideshowData.length) {
          ind = 0;
          slideshow.value.style.left = 0;
        }
        move(slideshow.value, "left", -550 * ind, 10, function () {
          allDot();
        });
      }, 3000);
    }
    // 轮播选择点击事件
    function slideshowSelectClick(index: number) {
      clearInterval(timer);
      ind = index;
      allDot();
      move(slideshow.value, "left", -550 * ind, 100, function () {
        loopSlideshow();
      });
    }
    onMounted(() => {
      // 轮播
      if (slideshow.value) {
        slideshow.value.style.width = 550 * slideshowData.length + "px"; //定义轮播宽度
        loopSlideshow(); // 无限循环轮播图
      }
    })
    return {
      slideshowData, //轮播数据
      slideshow, //获取轮播ref
      slideshowSelectImg, //获取轮播下方选择ref
      slideshowSelectClick, //轮播选择点击事件
    }
  },
})
</script>


<style lang="less" scoped>
    // 轮播
    .slideshowBox {
      width: 550px;
      height: 700px;

      .box {
        width: 550px;
        height: 550px;
        overflow: hidden;

        .slideshow {
          height: 550px;
          position: relative;
          left: 0;

          img {
            width: 550px;
            height: 550px;
          }
        }

      }
    }

    // 轮播下的选择
    .slideshowSelect {
      width: 400px;
      height: 80px;
      margin-top: 50px;
      display: flex;
      justify-content: space-between;

      img {
        width: 80px;
        height: 80px;
        cursor: pointer;
        margin-right: 10px;
        border: 2px solid transparent;
        box-sizing: border-box;
      }

      &>img:last-child {
        display: none;
      }

      .border {
        border: 2px solid red;
      }
    }
    
</style>

slideshow.ts文件

// 轮播工具
function getStyle(obj: any, name: string) {
  return getComputedStyle(obj, null)[name as any];
}
function move(obj: any, attr: string, target: number, speed: number, callback: any): any {
  clearInterval(obj.timer);
  var current = parseInt(getStyle(obj, attr));
  if (current > target) {
    speed = -speed;
  }
  obj.timer = setInterval(function () {
    var oldValue = parseInt(getStyle(obj, attr));
    var newValue = oldValue + speed;
    if ((speed < 0 && newValue < target) || (speed > 0 && newValue > target)) {
      newValue = target;
    }
    obj.style[attr] = newValue + "px";
    if (newValue == target) {
      clearInterval(obj.timer);
      callback && callback();
    }
  }, 30);
}
export default move;