前言:這是筆者學習之后自己的理解與整理。如果有錯誤或者疑問的地方,請大家指正,我會持續更新!
滾動 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 元素內容的實際尺寸;但是由於各個瀏覽器表現不一樣,分為以下幾種情況:
- 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; 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>