原生JS和CSS实现滚动轮播图的实现思路(附带指示器)

发布于:2022-12-15 ⋅ 阅读:(923) ⋅ 点赞:(0)

我们要实现的效果图如下:(图片截取自英雄联盟官网https://lol.qq.com/main.shtml)
在这里插入图片描述

(想要直接copy代码的同学,直接跳到最后的☆☆☆最终代码标识处)

我们来说说实现思路:
这个效果的背后逻辑就是一个盒子里,装着一个比它还要大的盒子,只是溢出部分用overflow:hidden隐藏掉了,只是我们看不到,但一直都在。外盒子宽度设置500px,内盒子的宽度要设置外盒子宽度的倍数即500的倍数(宽度自定,如下效果图中宽度是500px*5)
如下图
在这里插入图片描述
要做到溢出部分隐藏且不占空间,我们采用绝对定位实现
外盒子设置position:relative;overflow:hidden;
内盒子设置position:absolute;left:0px;top:0px;

第二步:如何滚动起来:定时器setInterval
利用setInterval让内盒子每过几秒就向左移动500px;(这里的向左移动是一个过程,所以我们需要在外盒子上加上属性transition: 0.5s;意思就是元素从一个状态变化到另一个状态所需要的时间,在这里就是向左移动500px需要0.5s)
转化为代码就是向左移动就是left = left - 500;
代码实现就是:定义一个全局遍历记录left = 0,定一个全局变量记录每次需要移动的距离width = 500,让内盒子每2秒向左移动一次,移动到-2000的位置时回到最初的位置

<script>
let width = 500;
let inditor = 0;//这里我们采用指示器的方法,有利于扩展,初始值为0也就是第一个轮播图的下标
let bannerList = document.getElementById("banner-list"); //内盒子的dom对象
window.onload=function(){
	  var interval = setInterval(function(){
	  	if(inditor >= 4){
	  		//如果下标到达了最后一个,令inditor = -1;因为定时器每次都会最后加1,所以这里等于-1后+1刚才等于0,跳到了第一个		
	  		inditor = -1;
		 }
		 //指示器代表轮播图的下标,每次+1,到最后回到0
		 inditor++;
		 //操作内盒子的dom对象,使得内盒子向左移动	
		 bannerList.style.left = -(width*inditor) + "px";
	 },2000);
</script>

在这里插入图片描述
(这里看起来有点卡顿是因为gif图的原因,实际上滚动的非常丝滑)

第三步:鼠标上浮到对应的指示位置,轮播图会作出对应的移动
到这里我们就需要采用到JS了,从效果图来分析
需求1.鼠标移动到第i个指示器时,内盒子马上要移动到对应的那张图,且鼠标没有移出时要一直停留在那张图上
需求2.鼠标移出时轮播图继续按照原来的规律开始滚动
需求3.轮播图滚动到第i张图片时,第i个指示器高亮显示

代码实现->需求1,2:

<script>
		//指示器下标
		let inditor = 0;
		//移动距离
		let width = 500;
		//内盒子dom对象
		let bannerList = document.getElementById("banner-list");
		//指示器dom对象
		let indicatorList = document.getElementById("indicator-list");
		//定时器设置为全局变量,因为鼠标上浮时需要清空定时器,默认值为null
		let interval = null;
		//也将定时器中的方法抽出来存为全局变量,方便后续拓展
		let intervalFun = function(){
				if(inditor == 4){
					inditor = -1;
				}
				inditor++;
				bannerList.style.left = -(width*inditor) +"px";
				
		};
		//页面初始化时
		window.onload=function(){
		 //为指示器添加监听事件
4		 addListener();
		//开始滚动
		 interval = setInterval(intervalFun,2000);
		
	//鼠标移入指示器时,index为鼠标移入时该指示器的下标
	function mouseIn(index){
			//鼠标指示器时,应该清空定时器
			clearInterval(interval);
			//并且置空
			interval = null;
			//使得当前的指示器标识 = 鼠标移入的这个指示器的标识
			inditor = index;
			//使得轮播图滚动至鼠标移入指示器对应的轮播图中
			bannerList.style.left = -(width*inditor) +"px";
	}
	//鼠标移出指示器时,index为鼠标移入时该指示器的下标
	function mouseOut(index){
			//鼠标移出指示器后,轮播图按照原来的规律继续滚动
		   interval = setInterval(intervalFun,2000);
	}
	//为指示器添加鼠标移入和移出事件
	function addListener(){
			//获得指示器dom对象的子元素集合
			var childrens = indicatorList.children;
			//遍历子元素
			for(var i = 0 ; i < childrens.length; i++){
				//这里为什么要写这么复杂,很多人会问写一个匿名方法不行吗?
				/*
					 如果我是这样写
					 childrens[i].onmouseover = function(){
						 //鼠标指示器时,应该清空定时器
						clearInterval(interval);
						//并且置空
						interval = null;
						//使得当前的指示器标识 = 鼠标移入的这个指示器的标识
						inditor = index;
						//使得轮播图滚动至鼠标移入指示器对应的轮播图中
			 			bannerList.style.left = -(width*inditor) +"px";
					 };
					 这样写会导致i的值一直是length的最大值,也就是产生了闭包的问题
					 所以我们只能把函数变量化再采用bind函数来解决这个问题
				 */
				var bindInFun = mouseIn.bind(this,i);
				var bindOutFun = mouseOut.bind(this,i);
				//鼠标移入
				childrens[i].onmouseover = bindInFun;
				//鼠标移出
				childrens[i].onmouseout = bindOutFun;
			
			}
	}
</script>

代码实现->需求3:轮播图滚动到第i张图片时,第i个指示器高亮显示

<script>
	//写一个方法来使当前自动滚动的轮播图对应的指示器高亮显示,然后将这个方法加入到页面初始化,定时器方法最后,和鼠标移入监听方法最后
	function indicatorListChange(){
			var childs = indicatorList.children;
			for(var i = 0 ; i < childs.length; i++){
				childs[i].style.backgroundColor = "#1E9FFF";
				if(i == inditor){
					childs[i].style.backgroundColor = "blue";
				}
			}
  }
</script>

☆☆☆最终代码

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			*{
				padding: 0;
				margin: 0;
				box-sizing: border-box;
			}
			.all-content{
				width: 700px;
				height: 200px;
				background-color: #DCDCDC;
				margin: 0 auto;
				margin-top: 100px;
			}
			
			.all-content>div{
				float: left;
			}
			.left-content,.right-content{
				height: 100%;
				width: 100px;
				border:5px #FF0000 solid;
			}
			
			.banner-content{
				height: 100%;
				width: 500px;
				position: relative;
				overflow: hidden;
			}
			.banner-indicator{
				list-style-type: none;
				height: 30px;
				width: 500px;
				background-color: #1E9FFF;
				position: absolute;
				left: 0px;
				bottom: 0px;
				color: white;
			}
			.banner-indicator>li{
				height: 30px;
				width: 100px;
				text-align: center;
				line-height: 30px;
				float: left;
				border: 1px solid white;
			}
			
			.banner-indicator>li:hover{
				background-color: blue;
				cursor: pointer;
			}
			
			.banner-list{
				list-style-type: none;
				height: 170px;
				position:absolute;
				left: 0px;
				top: 0px;
				width: 2500px;
				background-color: plum;
				transition: 0.5s;
			}
			.banner-list>li{
				height: 100%;
				width: 500px;
				float: left;
			}
			
		</style>
	</head>
	<body>
		<div class="all-content">
			<div class="left-content">
				<h1>左边内容</h1>
			</div>
			<div class="banner-content">
				<ul id="banner-list" class="banner-list">
					<li style="background-color: red;"></li>
					<li style="background-color: yellow;"></li>
					<li style="background-color: blue;"></li>
					<li style="background-color: green;"></li>
					<li style="background-color: purple;"></li>
				</ul>
				<ul id="indicator-list" class="banner-indicator">
					<li>第1张</li>
					<li>第2张</li>
					<li>第3张</li>
					<li>第4张</li>
					<li>第5张</li>
				</ul>
			</div>
			<div class="right-content">
				<h1>右边内容</h1>
			</div>
		</div>
	</body>
	
	<script>
		let inditor = 0;
		let width = 500;
		let bannerList = document.getElementById("banner-list");
		let indicatorList = document.getElementById("indicator-list");
		let interval = null;
		let intervalFun = function(){
					
					if(inditor == 4){
						inditor = -1;
					}
					inditor++;
					bannerList.style.left = -(width*inditor) +"px";
					indicatorListChange();
					
					
			};
		window.onload=function(){
		  addListener();
		  indicatorListChange();
		  //setInterval(indicatorListChange,0);
		  interval = setInterval(intervalFun,2000);
		   
		}
		
		
		function mouseIn(index){
			console.log(index);
			clearInterval(interval);
			interval = null;
			inditor = index;
			bannerList.style.left = -(width*inditor) +"px";
			indicatorListChange();
		}
		
		function mouseOut(index){
		   interval = setInterval(intervalFun,2000);
		}
		
		function addListener(){
			var childrens = indicatorList.children;

			for(var i = 0 ; i < childrens.length; i++){
				var bindInFun = mouseIn.bind(this,i);
				var bindOutFun = mouseOut.bind(this,i);
				childrens[i].onmouseover = bindInFun;
				childrens[i].onmouseout = bindOutFun;
			
			}
		}
		
		function indicatorListChange(){
			var childs = indicatorList.children;
			for(var i = 0 ; i < childs.length; i++){
				childs[i].style.backgroundColor = "#1E9FFF";
				if(i == inditor){
					childs[i].style.backgroundColor = "blue";
				}
			}
		}
	
	</script>
</html>

在这里插入图片描述

很多框架现在已经封装了这样的轮播图,这里只是向大家展示一下我个人的实现思路,有更好的解决方案欢迎来评论区留言!

本文含有隐藏内容,请 开通VIP 后查看