滚动 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{ 100px; height: 100px; padding: 10px; margin: 10px; border: 1px solid black; } #noOverScroll{ 100px; height: 100px; padding: 10px; margin: 10px; border: 1px solid black; overflow:scroll; font-size:20px; line-height:1; } #overScroll{ 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{ 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 元素内容的实际尺寸;但是由于各个浏览器表现不一样,分为以下几种情况:
- html 元素没有滚动条时,IE 和 firefox 的 client 和 scroll 属性始终相同,且返回可视区的尺寸大小;而 chrome 和 safari 不一样,clientHeight 返回可视区域大小,而 scrollHeight 返回元素内容大小;
- 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; 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; 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; 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:'回到顶部'; 40px; color:peru; font-weight:bold; } .directTop{ visibility: visible; display:inline-block; margin-top: 20px; height:20px; 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; if (e.wheelDelta) { //IE,Chrome 滑轮事件使用wheelDelta值表示表示滚轮方向,(120)表示向上, (-120)表示向下 if (e.wheelDelta > 0) { //当滑轮向上滚动时 console.log("滑轮向上滚动"); } if (e.wheelDelta < 0) { //当滑轮向下滚动时 console.log("滑轮向下滚动"); } } else if (e.detail) { //firefox事件的event对象使用detail值表示滚轮反向,(-3)表示向上,(3)表示向下。 if (e.detail> 0) { //当滑轮向上滚动时 console.log("滑轮向上滚动"); } if (e.detail< 0) { //当滑轮向下滚动时 console.log("滑轮向下滚动"); } } } //给页面绑定滑轮滚动事件 if (document.addEventListener) { document.addEventListener('DOMMouseScroll', scrollFunc, false); } //滚动滑轮触发scrollFunc方法 window.onmousewheel = document.onmousewheel = scrollFunc; </script>