这个问题是早前自己玩轮播图时遇到的,查了些资料,但大多都对不上我的问题,最后在知知乎乎那里看到了解释。解释是这样说的:
页面切走,有的浏览器会正常走定时器,正常更新排版视图。有的则放慢定时器,停止排版视图更新,甚至有插电和不插电的笔记本是否进入节能模式,浏览器为了节能,其优化策略都会产生调整,比如定时器精度变化.。如果代码没考虑到这些问题,可能会出岔子,个人建议,你的动画体系要以帧为主要核心。而不是以时间,见过市面上大多数动画库都错误的把时间作为缓动核心...
可以按照第一句解释来看,就出在浏览器对定时器的安排上了,有的浏览器看着你在它面前,它就好好给你走定时器,你一不看它去看别的页面了,它就偷懒不走或放慢定时器了,当咱们再回来的时候,它发现咱回来看它了,它就把堆积的定时器一统一块执行了,好家伙,这能不乱吗。
硬核解决方案就是监测咱看没看它
// 回来到当前页面,清除残留定时器的影响,执行定时器
window.onfocus=function(){
clearInterval(timer)
timer=setInterval(function(){
button_right.click()
},2000)
}
// 离开当前页面清除定时器,避免定时器生成堆积
window.onblur=function(){
clearInterval(timer);
}
li,i,ul{
list-style: none;
margin: 0;
padding: 0;
}
.swiper{
margin: 100px auto;
overflow: hidden;
width: 1226px;
height: 460px;
position: relative;
}
.swiper ul{
position: absolute;
top: 0;
left: 0;
height: 460px;
width: 600%;
}
.swiper ul li{
width: 1226px;
height: 460px;
float: left;
}
.swiper img{
display: block;
width: 100%;
height: 100%;
}
/* 左右按钮 */
.swiper span{
font-size: 25px;
display: block;
width: 50px;
height: 50px;
line-height: 50px;
text-align: center;
color: #ccc;
margin-top: -25px;
position: absolute;
top: 50%;
/* 先隐藏,在鼠标进入轮播图区域的时候显示 */
display: none;
cursor: pointer;
}
.swiper .button-right{
right: 0;
}
.swiper .button-left{
left: 0;
}
.swiper span:hover{
background-color: #e0e0e0;
color: black;
}
/* 小圆圈 */
.bullets{
position: absolute;
bottom: 30px;
right: 60px;
width: 300px;
height: 20px;
text-align: right;
}
.bullets i{
display: inline-block;
height: 10px;
width: 10px;
border: 3px solid #cccccc;
background-color: #e0e0e0;
border-radius: 50%;
margin: 0 3px;
}
.bullets .active{
background-color: #FF7F50;
}
<div class="swiper">
<!-- 轮播的图片 -->
<ul></ul>
<!-- 左右按钮 -->
<span class="button-left"><</span>
<span class="button-right">></span>
<!-- 小圆圈 -->
<div class="bullets"></div>
</div>
// 定义一些中间值
let num=0//记录图片滚动,滚动一次就+1,或者点击小圈变到相应的index
let circle=0//记录小圈变化,滚动一次就+1,或者点击变到相应的index
let timer=null;
// 获取元素
let swiper=document.querySelector('.swiper')
let ul=document.querySelector('.swiper ul')
let bullets=document.querySelector('.bullets')
let button_left=document.querySelector('.button-left')
let button_right=document.querySelector('.button-right')
// 动态添加图片和小圈
let arr=['./images/slider(1).jpg', './images/slider(2).jpg', './images/slider(3).jpg', './images/slider(4).jpg',
'./images/slider(5).jpg']
let html=''
for(let i=0;i<arr.length;i++){
html+='<li><a><img src='+arr[i]+'></img></a></li>'
// 这里生成小圈
let ii=document.createElement('i')
ii.setAttribute('index',i)
bullets.appendChild(ii)
}
ul.innerHTML=html
// 克隆第一张图片放到最后这是为了实现无缝滚动效果
let last_li=ul.children[0].cloneNode(true)
ul.appendChild(last_li)
// 默认第一个小圈是active
bullets.children[0].className='active'
// 追加完克隆元素之后再重新赋值下,避免下文走ul.children把ul当作初始的无children的节点
ul=document.querySelector('.swiper ul')
// 控制左右按钮的显示与隐藏
swiper.addEventListener('mouseenter',function(){
button_left.style.display="block"
button_right.style.display="block"
// 鼠标进入的时候,不轮播
clearInterval(timer)
timer=null
})
swiper.addEventListener('mouseleave',function(){
button_left.style.display="none"
button_right.style.display="none"
// 出去的时候继续轮播
timer=setInterval(function(){
button_right.click()
},2000)
})
// 点击右边按钮
button_right.addEventListener('click',function(){
// 如果到了最后一张图片,就立马回到一开始的第一张,这两张图片一样
if(num==ul.children.length-1){
num=0
ul.style.transition='none'
ul.style.transform='translateX('+swiper.offsetWidth*-num+'px)'
// 改变了之后必须得重绘,不然没效果(过渡就会被后面的盖过)
}
num++
// 小圈改变
circle++
ul.style.transition='all 1s ease'
ul.style.transform='translateX('+swiper.offsetWidth*-num+'px)'
if(circle==bullets.children.length) circle=0
circleChange()
})
// 点击左边的按钮
button_left.addEventListener('click',function(){
// 和右移差不多
if(num==0){
num=ul.children.length-1
ul.style.transition='all 0s'
ul.style.transform='translateX('+swiper.offsetWidth*-num+'px)'
// 改变了之后必须得重绘,不然没效果(过渡就会被后面的盖过)
}
num--
ul.style.transition='all 1s ease'
ul.style.transform='translateX('+swiper.offsetWidth*-num+'px)'
// 小圈改变
circle--
if(circle<0) circle=bullets.children.length-1
circleChange()
})
// 老关键了这一步,动画结束后就开始判断当前的num
// 否则会出现index=5的之后直接translateX越过0px变为-1*swiper.offsetWidth px
ul.addEventListener("transitionend",() => {
if(num > 4) {
num = 0
ul.style.transition = "none";// 将动画置空,否则下面这个translateX的设置会触发动画变换到0px的位置,而不是瞬移
ul.style.transform = 'translateX('+swiper.offsetWidth*-num+'px)';
}
},false)
// 点击小圈的时候也可以控制播放(这里可以在生成小圈的时候直接加监听,也可以在这里)
for(let i=0;i<bullets.children.length;i++){
bullets.children[i].addEventListener('click',function(){
// 得到小圈的index
circle=this.getAttribute('index')
// 调用下面定义好的函数
circleChange()
num=circle
ul.style.transform='translateX('+swiper.offsetWidth*-num+'px)'
})
}
// 小圈的改变
function circleChange(){
for(let i=0;i<bullets.children.length;i++){
bullets.children[i].className=''
}
bullets.children[circle].className='active'
}
// 自动轮播
timer=setInterval(function(){
button_right.click()
},2000)
// 避免页面切换动画累积影响效果
window.onfocus=function(){
clearInterval(timer)
timer=setInterval(function(){
button_right.click()
},2000)
}
window.onblur=function(){
clearInterval(timer);
}