zoukankan      html  css  js  c++  java
  • jacascript 滚动 scroll 与回到顶部

    前言:这是笔者学习之后自己的理解与整理。如果有错误或者疑问的地方,请大家指正,我会持续更新!

    滚动 scroll

      scrollHeight 表示元素的总高度,包括由于溢出而无法展示在网页的不可见部分

      scrollWidth 表示元素的总宽度,包括由于溢出而无法展示在网页的不可见部分

      没有滚动条时,scroll 和 client 属性的结果相等,即 scrollWidth= padding + width; scrollHeight= padding + height;

      存在滚动条时,但元素设置宽高大于等于元素内容宽高时(没有内容溢出),scroll 和 client 属性的结果相等,滚动条是有宽度的

      存在滚动条,但元素设置宽高小于元素内容宽高(存在内容溢出),scroll 属性大于 client 属性;

      scrollHeight 属性存在兼容性问题,chrome 和 safari 浏览器中,scrollHeight 包含 padding-bottom;而 IE 和 firefox 不包含 padding-bottom;

            <style type="text/css">
                *{padding: 0;margin: 0;}
                #noScroll{
                    width: 100px;
                    height: 100px;
                    padding: 10px;
                    margin: 10px;
                    border: 1px solid black;
                }
                #noOverScroll{
                    width: 100px;
                    height: 100px;
                    padding: 10px;
                    margin: 10px;
                    border: 1px solid black;
                    overflow:scroll;
                    font-size:20px;
                    line-height:1;
                }
                #overScroll{
                    width: 100px;
                    height: 100px;
                    padding: 10px;
                    margin: 10px;
                    border: 1px solid black;
                    overflow:scroll;
                    font-size:20px;
                    line-height:200px;
                }
            </style>
            
            <div id="noScroll"></div>
            <div id="noOverScroll">内容</div>
            <div id="overScroll">内容</div>        
            
            <script>
                var oNoScroll = document.getElementById('noScroll');
                //没有滚动条时,scrollHeight与clientHeight属性结果相等,scrollWidth与clientWidth属性结果相等
                console.log(oNoScroll.scrollHeight);//120
                console.log(oNoScroll.scrollWidth);//120
                console.log(oNoScroll.clientHeight);//120
                console.log(oNoScroll.clientWidth);//120
                
                var oNoOverScroll = document.getElementById('noOverScroll');
                //存在滚动条时,但元素设置宽高大于等于元素内容宽高时(没有内容溢出),scroll 和 client 属性的结果相等;
                //103(120-17)
                console.log(oNoOverScroll.scrollHeight);//120
                console.log(oNoOverScroll.scrollWidth);//120
                console.log(oNoOverScroll.clientHeight);//120
                console.log(oNoOverScroll.clientWidth);//120        
    
                var oOverScroll = document.getElementById('overScroll');
                //存在滚动条,但元素设置宽高小于元素内容宽高,即存在内容溢出的情况时,scroll属性大于client属性
                //scrollHeight 属性存在兼容性问题,chrome 和 safari 浏览器中,scrollHeight 包含 padding-bottom;而 IE 和 firefox 不包含 padding-bottom;
                //chrome/safari:220(200+10+10)
                //firefox/IE:210(200+10)
                console.log(oOverScroll.scrollHeight);//220
                //103(120-17)
                console.log(oOverScroll.scrollWidth);//103
                //103(120-17)
                console.log(oOverScroll.clientHeight);//103
                console.log(oOverScroll.clientWidth);//103    
            </script>

      scrollTop 属性表示隐藏在内容区域上方的像素数。元素未滚动时,scrollTop 的值为0,如果元素被垂直滚动了,scrollTop 的值大于0,且表示元素上方不可见内容的像素宽度;

      scrollLeft 属性表示隐藏在内容区域左侧的像素数。元素未滚动时,scrollLeft 的值为0,如果元素被水平滚动了,scrollLeft 的值大于0,且表示元素左侧不可见内容的像素宽度;

      当滚动条滚动到内容底部时,scrollHeight == scrollTop + clientHeight;

      可以通过控制 scrollTop、scrollLeft,控制滚动条;(第一种控制滚动条的方法

    <style type="text/css">
                #test{
                    width: 100px;
                    height: 100px;
                    padding: 10px;
                    margin: 10px;
                    border: 1px solid black;
                    overflow:scroll;
                    font-size:20px;
                    line-height:200px;
                }
            </style>
            <div id="test">内容</div>
            <button id='btnDown'>向下滚动</button>
            <button id='btnUp'>向上滚动</button>
            
            <script>
                var oTest = document.getElementById('test');
                var oBtnDown = document.getElementById('btnDown');
                var oBtnUp = document.getElementById('btnUp');
                oBtnDown.onclick = function(){
                    oTest.scrollTop += 10;
                }
                oBtnUp.onclick = function(){
                    oTest.scrollTop -= 10;
                }
            </script>

    页面尺寸

      document.documentElement.clientHeight 表示页面的可视区域的尺寸;

      document.documentElement.scrollHeight 表示 html 元素内容的实际尺寸;但是由于各个浏览器表现不一样,分为以下几种情况:

    1. html 元素没有滚动条时,IE 和 firefox 的 client 和 scroll 属性始终相同,且返回可视区的尺寸大小;而 chrome 和 safari 不一样,clientHeight 返回可视区域大小,而 scrollHeight 返回元素内容大小;
    2. html 元素存在滚动条时,各个浏览器都表现正常。clientHeight 返回可视区域大小,而 scrollHeight 返回元素内容大小;

      因此要取得文档实际高度时要取得 <html> 元素的 scrollHeight 和 clientHeight 的最大值

            <script type="text/javascript">
                var docHeight = Math.max(document.documentElement.scrollHeight,document.documentElement.clientHeight);
                var docWidth  = Math.max(document.documentElement.scrollWidth,document.documentElement.clientWidth);
            </script>

    页面滚动

      理论上,通过 document.documentElement.scrollTop 和 scrollLeft 可以反映和控制页面的滚动;但是 chrome 和 safari 浏览器是通过 document.body.scrollTop 和scrollLeft 来控制的;

      所以,页面的滚动高度兼容写法是

            <script type="text/javascript">
                var docScrollTop = document.documentElement.scrollTop || document.body.scrollTop;
            </script>

      可以利用 scrollTop 来实现回到顶部的功能(第一种回到顶部的方法);

        <body style="height:1000px">
            <button id='btn' style="position:fixed">回到顶部</button>
            
            <script>
                var oBtn = document.getElementById('btn');
                function scrollTop(){
                    var docScrollTop = document.documentElement.scrollTop || document.body.scrollTop;
                    if(docScrollTop != 0){
                        document.body.scrollTop = document.documentElement.scrollTop = 0;
                    }
                }
                oBtn.onclick = scrollTop;
            </script>
        </body>

      还有两个 window 的只读属性可以获取整个页面滚动的像素值,它们是 pageXOffset 和 pageYOffset;IE8及以下浏览器不支持

      window.pageXOffset 表示水平方向上页面滚动的像素值;

      window.pageYOffset 表示垂直方向上页面滚动的像素值;

    滚动方法

    scrollTo(x,y)

      scrollTo(x,y) 方法滚动当前 window 中显示的文档,让文档中由坐标 x 和 y 指定的点位于显示区域的左上角;

      第二种回到顶部的方法

        <body style="height:1000px">
            <button id='btn' style="position:fixed">滚动</button>
            <script>
                var oBtn = document.getElementById('btn');
                oBtn.onclick = function(){
                    scrollTo(0,0);
                }
            </script>
        </body>

    scrollBy(x,y)

      scrollBy(x,y) 方法滚动当前 window 中显示的文档,x 和 y 指定滚动的相对量;

      第二种控制滚动条的方法

      只要把当前页面的滚动长度 document.body.scrollTop 作为参数,逆向滚动(把滚动长度设为 y,并且为负值),则可以实现第三种回到顶部的效果;

        <body style="height:1000px">
            <button id='btnDown' style="position:fixed">向下滚动</button>
            <button id='btnUp' style="position:fixed;top:40px">向上滚动</button>
            <script>
                var oBtnDown = document.getElementById('btnDown');
                var oBtnUp = document.getElementById('btnUp');
                oBtnDown.onclick = function(){
                    scrollBy(0,10);
                }
                oBtnUp.onclick = function(){
                    scrollBy(0,-10);
                }
            </script>
        </body>

    scrollIntoView()

      Element.scrollIntoView() 方法滚动当前元素,进入浏览器的可见区域;

      该方法可以接受一个布尔值作为参数。如果为true,表示元素的顶部与当前区域的可见部分的顶部对齐(前提是当前区域可滚动);如果为false,表示元素的底部与当前区域的可见部分的尾部对齐(前提是当前区域可滚动)。如果没有提供该参数,默认为true

      第四种回到顶部的方法

    <style type="text/css">
            *{padding: 0;margin: 0;}
            #test{
                height:100px;
                width:100px;
                position:absolute;
                left:0;
                top:200px;
                background-color:green;
            }
            #btnTop{
                position:fixed;
            }
            #btnBottom{
                position:fixed;
                top:40px;
            }
        </style>
        <body style="height:1000px">
            <div id="test"></div>
            <button id='btnTop'>滚动到页面开头</button>
            <button id='btnBottom'>滚动到页面结尾</button>
            
            <script>
                var oTest = document.getElementById('test');
                var oBtnTop = document.getElementById('btnTop');
                var oBtnBottom = document.getElementById('btnBottom');
                oBtnTop.onclick = function(){
                    oTest.scrollIntoView();
                };
                oBtnBottom.onclick = function(){
                    oTest.scrollIntoView(false);
                }
            </script>
        </body>

    scrollIntoViewIfNeeded(alignCenter)

      scrollIntoViewIfNeeded(alignCenter) 方法只在当前元素在视口中不可见的情况下,才滚动浏览器窗口或容器元素,最终让它可见。如果当前元素在视口中可见,这个方法什么也不做;该方法只有 chrome 和 safari 支持

      如果将可选的 alignCenter 参数设置为 true,则表示尽量将元素显示在视口中部(垂直方向);尽量的意思是可能不成功,比如有元素有一半显示,一半隐藏,那么只会全部显示,但不会显示在视口中部;

    <style type="text/css">
            #test{
                height:100px;
                width:100px;
                /*position:absolute;
                left:0;
                top:500px;*/
                background-color:green;
            }
            #btn{
                position:fixed;
                top: 0;
            }
        </style>
        <body>
            <ul>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
            </ul>
            <div id="test"></div>
            <ul>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
            </ul>
            <button id='btn'>滚动到页面中间</button>
            <script>
                var oTest = document.getElementById('test');
                var oBtn = document.getElementById('btn');
                
                oBtn.onclick = function(){
                    oTest.scrollIntoViewIfNeeded();
                };
            </script>
        </body>

    scrollByLines(lineCount)

      scrollByLines(lineCount) 方法将元素的内容滚动指定的行髙,lineCount 值可以是正值, 也可以是负值,该方法只有 safari 支持

    scrollByPages(pageCount)

      scrollByPages(pageCount) 方法将元素的内容滚动指定的页面高度,具体高度由元素的高度决定;该方法只有safari支持

    回到顶部

      前文有很多种方法可以实现回到顶部功能,有时候需要为回到顶部增加动画效果,滚动条以一定的速度回滚到顶部;

      动画有两种:一种是CSS动画,需要有样式变化配合 transition;一种是 javascript 动画,使用定时器来实现;  

      在前文的实现中,scrollTop、scrollTo() 和 scrollBy() 方法可以增加动画,且由于无样式变化,只能增加javascript动画;

      定时器又有 setInterval、setTimeout 和 requestAnimationFrame 这三种可以使用,下面使用性能最好的定时器 requestAnimationFrame 来实现;

      IE9及以下浏览器不支持该方法,可以使用 setTimeout 来兼容;

      由于 scrollTop、scrollBy() 和 scrollTo()方法,都以 scrollTop 值是否减少为0作为动画停止的参照,且三个动画的原理和实现都基本相似,性能也相似。最终,以最常用的scrollTop属性实现动画增强效果;

      当然,如果觉得50的速度不合适,可以根据实际情况进行调整;

        <style>
            *{padding: 0;margin: 0;}
            .goTop{
                position:fixed;
                right:10px;
                bottom: 10px;
                height:50px;
                width: 50px;    
                text-align:center;
                background-color: lightblue;
                border-radius: 20%;
                overflow: hidden;
            }
            .goTop:hover:before{
                top:50%;
            }
            .goTop:hover .directTop{
                visibility: hidden;
            }
            .goTop:before{
                position: absolute;
                top: -50%;
                left: 50%;
                transform: translate(-50%,-50%);
                content:'回到顶部';
                width: 40px;
                color:peru;
                font-weight:bold;
            }    
            .directTop{
                visibility: visible;
                display:inline-block;
                margin-top: 20px;
                height:20px;
                width: 20px;
                border: 3px solid;
                border-color: white transparent transparent white;
                transform:rotate(45deg);
            }
        </style>
    
        <body style="height:2000px;">
            <div class="goTop">
                <div class="directTop"></div>
            </div>    
            <script>
                var timer  = null;
                var oGoTop = document.getElementsByClassName('goTop')[0];
                oGoTop.onclick = function(){
                    cancelAnimationFrame(timer);
                    timer = requestAnimationFrame(function fn(){
                        var oTop = document.body.scrollTop || document.documentElement.scrollTop;
                        if(oTop > 0){
                            document.body.scrollTop = document.documentElement.scrollTop = oTop - 50;
                            timer = requestAnimationFrame(fn);
                        }else{
                            cancelAnimationFrame(timer);
                        }    
                    });
                }
            </script>
            
            <!--setTimeout 兼容写法-->
            <!--<script>
                var timer  = null;
                var oGoTop = document.getElementsByClassName('goTop')[0];
                oGoTop.onclick = function(){
                    clearTimeout(timer);
                    timer = setTimeout(function fn(){
                        var oTop = document.body.scrollTop || document.documentElement.scrollTop;
                        if(oTop > 0){
                            document.body.scrollTop = document.documentElement.scrollTop = oTop - 50;
                            timer = setTimeout(fn,0);
                        }else{
                            clearTimeout(timer);
                        } 
                    },0);    
                }
            </script>-->
        </body>

       

    滚动事件

      scroll 事件是在 window 对象上发生的,它表示的是页面中相应元素的变化。当然,scroll 事件也可以用在有滚动条的元素上;

        <body style="height:1000px">
            <div id="result" style="position:fixed;top:10px;"></div>
            <script>
                var oResult = document.getElementById('result');
                window.onscroll = function(){
                    var docScrollTop = document.documentElement.scrollTop || document.body.scrollTop;
                    result.innerHTML = '页面的scrollTop:' + docScrollTop;
                }
            </script>    
        </body>

       有时候需要判断滚动方向

        <script type="text/javascript">
            function scroll( fn ) {
                var beforeScrollTop = document.documentElement.scrollTop || document.body.scrollTop,
                    fn = fn || function() {};
                window.addEventListener("scroll", function() {
                    var afterScrollTop = document.documentElement.scrollTop || document.body.scrollTop,
                        delta = afterScrollTop - beforeScrollTop;
                    if( delta === 0 ) return false;
                    fn( delta > 0 ? "down" : "up" );
                    beforeScrollTop = afterScrollTop;
                }, false);
            }
            scroll(function(direction) { 
                if(direction == 'down'){
                    console.log('向下');
                }else if(direction == 'up'){
                    console.log('向上');
                }
            });
        </script>

      JQuery判断滚动方向,

        <script type="text/javascript">
            function scroll( fn ) {
                var $window = $(window),
                    beforeScrollTop = $window.scrollTop(),
                    fn = fn || function() {};
            
                $window.scroll(function() {
                    var afterScrollTop = $window.scrollTop(),
                        delta = afterScrollTop - beforeScrollTop;
                    if( delta === 0 ) return false;
                    fn( delta > 0 ? "down" : "up" );
                    beforeScrollTop = afterScrollTop;
                });
            }
            scroll(function(direction) { 
                if(direction == 'down'){
                    console.log('向下');
                }else if(direction == 'up'){
                    console.log('向上');
                }
            });
        </script>

      还有一种方法,

           <script>  
                var scrollFunc = function (e) {  
                    var direct = 0;  
                    e = e || window.event;
                    //滚轮事件中有一个 wheelDelta 属性,当用户向前滚动鼠标滚轮时,wheelDelta 是120的倍数;当用户向后滚动鼠标滚轮时,wheelDelta 是 -120 的倍数;
                    //firefox 浏览器有关鼠标滚轮的信息则保存在 detail 属性中。当向前滚动鼠标滚轮时,这个属性的值是 -3 的倍数;当向后滚动鼠标滚轮时,这个属性的值是 3 的倍数。
                    if (e.wheelDelta > 0 || e.detail < 0) {   
                        console.log("滑轮向上滚动");  
                    }  
                    if (e.wheelDelta < 0 || e.detail > 0) { 
                        console.log("滑轮向下滚动");  
                    }  
                } 
                //firefox 浏览器不支持 mousewheel 事件,它支持 DOMMouseScroll 事件(该事件仅支持DOM2级事件处理程序的写法)
                if (document.addEventListener) {  
                    document.addEventListener('DOMMouseScroll', scrollFunc, false);  
                }  
                //滚动滑轮触发scrollFunc方法  
                window.onmousewheel = document.onmousewheel = scrollFunc;    
            </script>
  • 相关阅读:
    什么是 bean 的自动装配?
    什么是 Spring 的内部 bean?
    什么是 Spring 的 MVC 框架?
    Spring AOP and AspectJ AOP 有什么区别?
    解释 JDBC 抽象和 DAO 模块?
    volatile 类型变量提供什么保证?
    一个 Spring Bean 定义 包含什么?
    什么是 Spring MVC 框架的控制器?
    使用 Spring 访问 Hibernate 的方法有哪些?
    什么是 Callable 和 Future?
  • 原文地址:https://www.cnblogs.com/sspeng/p/6765612.html
Copyright © 2011-2022 走看看