html中dom元素滾動(dòng)條滾動(dòng)控制小結(jié)詳解

不知道大家有沒有遇到過(guò)這樣的需求,在某個(gè) dom
元素中添加新的子元素,然后要求如果新添加的新元素超出容器的范圍,那么我們需要自動(dòng)滾動(dòng)到新添加的子元素的位置,如下圖所示效果:
那么接下來(lái)我們一邊學(xué)習(xí)一些 dom
元素滾動(dòng)相關(guān)的知識(shí)點(diǎn),一邊實(shí)現(xiàn)一個(gè)上圖的效果和一些其他滾動(dòng)相關(guān)的功能。
需要了解的dom屬性和方法 scrollTop、clientHeight和scrollHeight
scrollTop
屬性是一個(gè)描述容器元素內(nèi)容的top值與容器元素( viewport
)視口頂部 top
值之間的差值,即容器中內(nèi)容向上滑動(dòng)后超出容器視口的部分??梢酝ㄟ^(guò)修改此屬性控制滾動(dòng)狀態(tài)。
clientHeight
是描述容器高度的 dom
屬性。
scrollHeight
是描述容器內(nèi)容高度的 dom
屬性。
三個(gè)屬性的關(guān)系如下圖所示:
getBoundingClientRect()
此方法用來(lái)獲取元素布局所需的一些幾何屬性,比如 left
、 right
、 top
、 bottom
、 height
、 width
等。
srollBy(x,y)
dom
容器的 scrollTo
方法可以用來(lái)直接控制滾動(dòng)條滾動(dòng)指定的距離。當(dāng)需要滾動(dòng)到指定元素時(shí),使用此方法比較方便。
srollTo(x,y)
dom
容器的 scrollTo
方法可以用來(lái)直接控制滾動(dòng)條滾動(dòng)到指定位置。在控制滾動(dòng)條滾動(dòng)到頂部或者底部的時(shí)候使用此方法比較方便。
實(shí)現(xiàn)滾動(dòng)控制 準(zhǔn)備
我們先準(zhǔn)備一個(gè) html
<!DOCTYPE html> <html> <head> <title>滾動(dòng)條設(shè)置詳解</title> <style> #scroll_container{ height: 500px; width: 500px; overflow-y: scroll; padding: 50px; box-sizing: border-box; } .scroll_item{ height: 200px; width: 500px; margin-top: 20px; background-color: aquamarine; display: flex; align-items: center; justify-content: center; } </style> </head> <body> <div id="scroll_container"> <div id="scroll_container"> <div id="item1" class="scroll_item"> <span>1</span> </div> <div id="item2" class="scroll_item"> <span>2</span> </div> <div id="item3" class="scroll_item"> <span>3</span> </div> <div id="item4" class="scroll_item"> <span>4</span> </div> <div id="item5" class="scroll_item"> <span>5</span> </div> </div> <button onclick="addItem()">添加一個(gè)元素</button> </div> </body> <script> let container=document.getElementById("scroll_container"); let index=5; //添加一個(gè)元素 function addItem(){ index+=1; let item=`<div id="${'item'+index}" class="scroll_item"> <span>${index}</span> </div>`; container.innerHTML+=item; setTimeout(()=>{ scrollToIndex(); }) } </script> </html>
上面的代碼包含一個(gè)可滾動(dòng)的區(qū)域,并可以為滾動(dòng)區(qū)域添加元素,也可以滾動(dòng)到指定的元素位置,大致效果如下圖。
使用scrollTop實(shí)現(xiàn)
基礎(chǔ)實(shí)現(xiàn)
之前已經(jīng)說(shuō)明過(guò) scrollTop
的含義,我們可以通過(guò)修改容器元素 scrollTop
值來(lái)控制滾動(dòng)條滾動(dòng)。 scrollTop
的值越大,滾動(dòng)條相對(duì)于原始狀態(tài)( scrollTop
為0時(shí))的滾動(dòng)距離越大。
了解了 scrollTop
的含義,我們就可以利用 scrollTop
來(lái)實(shí)現(xiàn)滾動(dòng)條的控制,那么我們先實(shí)現(xiàn)一個(gè)滾動(dòng)到底部的實(shí)現(xiàn),為上面的代碼添加一個(gè) scrollToBottom()
的方法:
function scrollToBottom(){ let y=container.scrollHeight-container.clientHeight; container.scrollTop=y; }
對(duì)應(yīng)的如果想要實(shí)現(xiàn)滾動(dòng)到頂部我們只需要設(shè)置 scrollTop
為0即可:
function scrollToTop(){ container.scrollTop=0; }
結(jié)合 getBoundingClientRect()
方法我們也可以輕松實(shí)現(xiàn)滾動(dòng)到指定元素,其中 getBoundingClientRect().top
表示子元素頂部距離父元素視口頂部的距離:
function scrollToElement(el){ container.scrollTop+=el.getBoundingClientRect().top; }
添加動(dòng)畫
滾動(dòng)到底部
但是上面代碼的滾動(dòng)未免太生硬了,我們可以為它添加一下動(dòng)畫效果,可以借助 setInterval()
實(shí)現(xiàn)一下。分析一下實(shí)現(xiàn)動(dòng)畫效果的過(guò)程,動(dòng)畫的實(shí)現(xiàn)無(wú)外乎是把一個(gè)變量的變化在一定的時(shí)間內(nèi)完成,因此我們首先需要知道兩個(gè)變量,變量( scrollTop
)偏移量和變化所需時(shí)間,而偏移量就是 scrollTop
的最終值減去原始值,變化時(shí)長(zhǎng)一般設(shè)置成可以修改的參數(shù)。了解了以上過(guò)程,我們先以滾動(dòng)到底部為例:
//首先編寫一個(gè)scrollToBottom函數(shù) function scrollToBottom(el){ if(!el){ el=container; } //原始值 let startTop=el.scrollTop; //最終值 let endTop=el.scrollHeight-el.clientHeight; //生成一個(gè)動(dòng)畫控制函數(shù) let scrollAnimationFn=doAnimation(startTop,endTop,300,el); //執(zhí)行動(dòng)畫,每10ms執(zhí)行一次 let interval=setInterval(()=>{ scrollAnimationFn(interval) },10) } /** * @description: 一個(gè)生成動(dòng)畫控制函數(shù)的工廠函數(shù)(使用閉包) * @param { startValue:變量原始值 endValue:變量最終值 duration:動(dòng)畫時(shí)長(zhǎng) el:執(zhí)行滾動(dòng)動(dòng)畫的元素 } * @return: null */ function doAnimation(startValue,endValue,duration,el){ //使用閉包保存變量dy和step(每次動(dòng)畫滾動(dòng)的距離) let dy=0; let step=(endValue-startValue)/(duration/10); //返回動(dòng)畫控制函數(shù) return function(interval){ dy+=step; if(dy>=endValue-startValue){ clearInterval(interval); } el.scrollTop+=step; } }
修改addItem函數(shù)添加滾動(dòng)到底部動(dòng)畫:
function addItem(){ index+=1; let item=`<div id="${'item'+index}" class="scroll_item"> <span>${index}</span> </div>`; container.innerHTML+=item; setTimeout(()=>{ // scrollToIndex(); scrollToBottom(container); }) }
然后為html加入一個(gè)滾動(dòng)到底部的按鈕:
<button onclick="scrollToBottom()">滾動(dòng)到底部</button>
滾動(dòng)到頂部
按照上面的方法也可以實(shí)現(xiàn)一個(gè)常用的帶動(dòng)畫滾動(dòng)到頂部:
//編寫一個(gè)scrollToTop函數(shù) function scrollToTop(el){ if(!el){ el=container; } //原始值 let startTop=el.scrollTop; //最終值 let endTop=0; //生成一個(gè)動(dòng)畫控制函數(shù) let scrollAnimationFn=doAnimation(startTop,endTop,300,el); //執(zhí)行動(dòng)畫,每10ms執(zhí)行一次 let interval=setInterval(()=>{ scrollAnimationFn(interval) },10) }
為了適配滾動(dòng)到底部我們需要修改一下動(dòng)畫停止的時(shí)機(jī)判斷,修改后的 doAnimation()
函數(shù)如下:
function doAnimation(startValue,endValue,duration,el){ //使用閉包保存變量dy和step(每次動(dòng)畫滾動(dòng)的距離) let dy=0; let step=(endValue-startValue)/(duration/10); return function(interval){ dy+=step; //這里改成使用絕對(duì)值判斷 if(Math.abs(dy)>=Math.abs(endValue-startValue)){ clearInterval(interval); } el.scrollTop+=step; } }
最后我們?cè)俳o html
添加一個(gè)滾動(dòng)到底部按鈕:
<button onclick="scrollToTop()">滾動(dòng)到頂部</button>
實(shí)現(xiàn)效果如下圖:
滾動(dòng)到指定元素
首先為html元素添加所需的按鈕和輸入框:
<input type="number" placeholder="請(qǐng)輸入要滾動(dòng)到的元素index" style="width: 200px;"/> <button onclick="scrollToElement()">滾動(dòng)到指定元素</button>
添加一個(gè)滾動(dòng)指定元素的動(dòng)畫執(zhí)行函數(shù):
function scrollToElement(containerEl,el){ if(!containerEl){ //父元素 containerEl=container; } if(!el){ //獲取到要滾動(dòng)到的元素 let input=document.getElementsByTagName('input')[0]; let id='item'+input.value; if(!input.value){ id='item'+index; } el=document.getElementById(id); } let startTop=containerEl.scrollTop; let endTop=startTop+el.getBoundingClientRect().top; let scrollAnimationFn=doAnimation(startTop,endTop,300,containerEl); let interval=setInterval(()=>{ scrollAnimationFn(interval) },10) }
實(shí)現(xiàn)效果如下:
使用scrollTo()實(shí)現(xiàn)
scrollTo(x,y)
的使用方法與 scrollTop
屬性的使用方法基本一致,父元素的 scrollTo()
方法可以控制滾動(dòng)條滾動(dòng)到指定位置,實(shí)際上相當(dāng)于設(shè)置 scrollTop
的值。舉個(gè)例子說(shuō)明一下:
//這里以y軸滾動(dòng)為例 element.scrollTo(0,y); element.scrollTop=y; //上面兩句的效果相同。
所以,使用 scrollTo()
方法控制滾動(dòng)條與使用scrollTop基本一致,我們只需要簡(jiǎn)單修改 doAnimation()
函數(shù),代碼如下:
function doAnimation(startValue,endValue,duration,el){ //使用閉包保存變量dy和step(每次動(dòng)畫滾動(dòng)的距離) let dy=0; let step=(endValue-startValue)/(duration/10); return function(interval){ dy+=step; if(Math.abs(dy)>=Math.abs(endValue-startValue)){ clearInterval(interval); } //el.scrollTop+=step;//這行代碼修改為如下 el.scrollTo(0,el.scrollTop+step); } }
執(zhí)行效果與使用 scrollTop
實(shí)現(xiàn)一致。
使用scrollBy()實(shí)現(xiàn)
基礎(chǔ)實(shí)現(xiàn)
我們同樣可以使用 scrollBy(x,y)
實(shí)現(xiàn)對(duì)滾動(dòng)條的控制,上面已經(jīng)說(shuō)明過(guò), scrollBy()
方法是控制滾動(dòng)條滾動(dòng)指定距離(注意不是位置)。使用scrollBy()可以很方便的實(shí)現(xiàn)滾動(dòng)到指定元素的需求,代碼如下:
function scrollToElement(containerEl,el){ //因?yàn)間etBoundingClientRect().top即為子元素頂部距離父元素頂部的距離,所以這個(gè)值就是子元素相對(duì)于父元素的偏移量,我們傳入這個(gè)值到scrollBy中,即滾動(dòng)到指定元素 containerEl.scrollBy(0,el.getBoundingClientRect().top); }
滾動(dòng)到底部:
function scrollToBottom(containerEl){ let dy=containerEl.scrollHeight-containerEl.clientHeight; containerEl.scrollBy(0,dy); }
滾動(dòng)到頂部
function scrollToTop(containerEl){ let dy=-(containerEl.scrollHeight-containerEl.clientHeight); containerEl.scrollBy(0,dy); }
添加動(dòng)畫
這里我們修改一下動(dòng)畫生成的函數(shù),因?yàn)檫@里我們 scrollBy()
的參數(shù)就是變量的偏移量,所以做出如下修改:
function scrollToBottom(containerEl){ if(!containerEl){ containerEl=container; } //dy即為偏移量 let dy=containerEl.scrollHeight-containerEl.clientHeight; let scrollAnimationFn=doAnimation(dy,300,containerEl); let interval=setInterval(()=>{ scrollAnimationFn(interval) },10) } function scrollToTop(containerEl){ if(!containerEl){ containerEl=container; } //dy即為偏移量 let dy=-(containerEl.scrollHeight-containerEl.clientHeight); let scrollAnimationFn=doAnimation(dy,300,containerEl); let interval=setInterval(()=>{ scrollAnimationFn(interval) },10) } function scrollToElement(containerEl,el){ if(!containerEl){ containerEl=container; } if(!el){ let input=document.getElementsByTagName('input')[0]; let id='item'+input.value; if(!input.value){ id='item'+index; } el=document.getElementById(id); } //dy即為偏移量 let dy=el.getBoundingClientRect().top; let scrollAnimationFn=doAnimation(dy,300,containerEl); let interval=setInterval(()=>{ scrollAnimationFn(interval) },10) } /** * @description: * @param {type} * @return: */ function doAnimation(dy,duration,el){ //使用閉包保存變量exe_dy和step等變量(每次動(dòng)畫滾動(dòng)的距離) let exe_dy=0;//已經(jīng)執(zhí)行的偏移量 let step=dy/(duration/10); return function(interval){ exe_dy+=step; if(Math.abs(exe_dy)>=Math.abs(dy)){ clearInterval(interval); } el.scrollBy(0,step); } }
執(zhí)行效果與使用 scrollTop
實(shí)現(xiàn)一致。
最后
以上:point_up_2:就是自己對(duì)dom滾動(dòng)條控制的詳細(xì)總結(jié)和講解,以及一些基本使用方法。
到此這篇關(guān)于html中dom元素滾動(dòng)條滾動(dòng)控制小結(jié)詳解的文章就介紹到這了,更多相關(guān)dom元素滾動(dòng)條滾動(dòng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持腳本之家!
相關(guān)文章
js利用dom-drag模擬flash滾動(dòng)條效果
用dom-drag來(lái)實(shí)現(xiàn)flash上比較常用的滾動(dòng)條效果,喜歡的朋友可以參考下。2010-07-19