javascript - 关于“回到顶部”的自动滚动和手动滚动的问题?
黄舟
黄舟 2017-04-11 12:35:00
0
2
327
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文件以外不断执行的另一个线程,不知道这个想法又是不是正确的?

黄舟
黄舟

人生最曼妙的风景,竟是内心的淡定与从容!

全員に返信(2)
刘奇

先简要的说两个点。
1.element.scrollTop会触发window.onscroll
2.单线程js的事件机制,即当前的所有js跑完才会执行事件队列中的回调函数,即事件1的回调函数中触发事件2事件1的回调函数不运行完是不会执行事件2的回调的
然后我慢慢写流程。

简化下你上面的代码

window.onscroll = function(){//窗口滚动事件
    if(!isTop){
        clearInterval(timer);
    }
    isTop = false;
}
scrollTop.onclick = function(){//按钮点击事件
    timer = setInterval(function(){//滚动定时器
        scrollTopByStep()//滚动一步,会触发上面的window.onscroll
        isTop =true;//用于阻止滚动事件清除定时器
        if(bodyScroll == 0){//到顶停止定时器
            clearInterval(timer);
        }
    },30);
}

暂且称window.onscroll事件1,其回调函数为函数1,定时器事件为事件2内的回调函数为函数2

1.先说只点击按钮而不手动滚动的情况。

函数1执行到scrollTopByStep会触发事件1,但是当前函数2还没执行完,所以函数1会在事件队列里等着,isTop置为true, bodyScroll == 0false;//这为函数2
然后执行函数1,!isTopfalse,不清除定时器。isTop置为false//这为函数1
然后等定时器的30ms到,再执行函数2,由此循环直到bodyScroll == 0
2.再说点击按钮向上滚动过程中手动滚动滚动条的情况。

本来函数执行顺序应该是函数2、函数1、函数2、函数1、函数2、函数1......(从第一种情况来说),然后手动滚动会再触发事件1,即事件队列里都会多一个事件1(即函数执行顺序里插入函数1),不论在什么时间触发即多在哪都会有函数2、函数1、函数1这么一个情况。所以顺着上面的请款说,执行完第一次函数1,还会执行一次函数1,此时!isToptrue,定时器清除。

いいねを押す +0
左手右手慢动作

理解没有错。

关于断点调试,我想应该是 onscroll 在一次滚轮时会触发多次事件,这应该很浏览器也有关系吧。

いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!