我们要实现的效果图如下:(图片截取自英雄联盟官网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>
很多框架现在已经封装了这样的轮播图,这里只是向大家展示一下我个人的实现思路,有更好的解决方案欢迎来评论区留言!