window.onload = function(){//窗口载入完毕事件
var scrollTop = document.getElementById("scrollTop-span");//返回顶部按钮
//返回顶部
var timer = null; //定义一个定时器
var isTop = true; //定义一个布尔值,判断是否到达顶部
window.onscroll = function(){//窗口滚动事件
//document.documentElement.scrollTop(IE)
//document.body.scrollTop(chrome)
var bodyScroll = document.documentElement.scrollTop || document.body.scrollTop;//获取滚动高度
if(bodyScroll >= 300){//如果滚动高度大于300,显示按钮
scrollTop.style.display = "inline";
}else{//否则隐藏
scrollTop.style.display = "none";
}
//判断当点击回到顶部按钮后,滚动条在回滚过程中,若手动滚动滚动条,则清除定时器
if(!isTop){
clearInterval(timer);
}
isTop = false;
}
scrollTop.onclick = function(){//按钮点击事件
timer = setInterval(function(){//滚动定时器
var bodyScroll = document.documentElement.scrollTop || document.body.scrollTop;//获取窗口滚动高度
/*用于设置速度差,产生缓动的效果
(如果Math.floor向下取整,需要转化为负数,滚动高度设置需要加上负值的速度差)
否则当快到顶部时,速度差向下取整等于0,滚动高度一直减去0,无法到达顶部,陷入死循环*/
var speed = Math.ceil(bodyScroll/10);
document.documentElement.scrollTop = document.body.scrollTop = bodyScroll - speed;//设置滚动高度
/*速度差使用向下取整时,应该这样写:
var speed = Math.ceil(bodyScroll/10);
document.documentElement.scrollTop = document.body.scrollTop = bodyScroll - speed;//设置滚动高度
*/
isTop =true; //用于阻止滚动事件清除定时器
if(bodyScroll == 0){//到顶停止定时器
clearInterval(timer);
}
},30);
}
}
在学习一个实例,其中“判断当点击回到顶部按钮后,滚动条在回滚过程中,若手动滚动滚动条,则清除定时器”这里有点不明白,或者说,我这样的理解是否正确?
我的理解是,当点击了“返回顶部”按钮后,执行的是定时器里的自动滚动,由于定时器里有“isTop =true;”,所以定时器不会停止;
而当我们使用了鼠标的滚轮,这里我把滚动鼠标滚轮也看成一个函数,执行的是“设置滚动高度”,只有这个设置而没有“isTop=true;”,所以定时器停止了。
总感觉,定时器的滚动和鼠标的滚动时两个分开的事件。
还有一个问题就断点调试的时候,当鼠标滚轮滚动时,isTop = false; 但是由于判断语句是在上面,那么此时不是应该继续往下执行代码吗?为什么反而跳回去执行判断语句呢? //补充,对于这个问题,多次断点后,想到一个问题,当点击了按钮后,执行定时器,这个时候就没有“onclick”什么事了,而定时器其实是游离于js文件以外不断执行的另一个线程,不知道这个想法又是不是正确的?
先简要的说两个点。
1.
element.scrollTop
会触发window.onscroll
2.单线程js的事件机制,即当前的所有js跑完才会执行事件队列中的回调函数,即事件1的回调函数中触发事件2,事件1的回调函数不运行完是不会执行事件2的回调的。
然后我慢慢写流程。
简化下你上面的代码
暂且称
window.onscroll
为事件1,其回调函数为函数1,定时器事件为事件2内的回调函数为函数2。1.先说只点击按钮而不手动滚动的情况。
函数1执行到
scrollTopByStep
会触发事件1,但是当前函数2还没执行完,所以函数1会在事件队列里等着,isTop
置为true
,bodyScroll == 0
为false
;//这为函数2然后执行函数1,
!isTop
为false
,不清除定时器。isTop
置为false
//这为函数1然后等定时器的30ms到,再执行函数2,由此循环直到
bodyScroll == 0
2.再说点击按钮向上滚动过程中手动滚动滚动条的情况。
本来函数执行顺序应该是函数2、函数1、函数2、函数1、函数2、函数1......(从第一种情况来说),然后手动滚动会再触发事件1,即事件队列里都会多一个事件1(即函数执行顺序里插入函数1),不论在什么时间触发即多在哪都会有函数2、函数1、函数1这么一个情况。所以顺着上面的请款说,执行完第一次函数1,还会执行一次函数1,此时
!isTop
为true
,定时器清除。理解没有错。
关于断点调试,我想应该是
onscroll
在一次滚轮时会触发多次事件,这应该很浏览器也有关系吧。