這個(gè)方法的主要應(yīng)用是懶加載(lazyload),無(wú)限加載(infinte scroll)
基于瀏覽器窗口的判斷 .getBoundingClientRect()
dom api .getBoundingClientRect()
可以獲取元素距離頁(yè)面頂部top的距離(top,bottom),還有距離頁(yè)面左側(cè)的距離(left,right)
因此我們監(jiān)聽(tīng)滾動(dòng)條事件,在滾動(dòng)條事件里面通過(guò) 判斷.getBoundingClientRect()
獲得的參數(shù)就能夠確定,元素是否進(jìn)入了可視區(qū)域內(nèi).
我們只需要判斷element的 bottom大于0,并且top小于頁(yè)面可視高度,就表明元素已經(jīng)進(jìn)入可視區(qū)域
頁(yè)面可視高度,可以用window.innerHeight獲取,注意是包括了滾動(dòng)條的高度. 還有一個(gè)outerHeight屬性則是包括了瀏覽器窗口的高度.
這里我的需求是一個(gè)toc插件,判斷目錄滾動(dòng)到那個(gè)標(biāo)題了,代碼實(shí)現(xiàn)如下
// 添加滾動(dòng)條監(jiān)聽(tīng)事件,隨著滾動(dòng)判斷標(biāo)題是否出現(xiàn)在可視區(qū)域
useEffect(() => {
function handleScrollToc() {
// 可視窗口的高度
const viewHeight = window.innerHeight
let currentIndex = 0
for (const index in headList) {
const clientRect = headList[index].node.getBoundingClientRect()
// |<—————————————————— 視口起點(diǎn)
// |——————rect.top—————|
// | |
// | rect.height |
// | |
// |—————rect.bottom———|
// 判斷元素是否在可視區(qū)域內(nèi)
if (clientRect.bottom >= 0 && clientRect.bottom < viewHeight) {
currentIndex = parseInt(index)
setActiveIndex(currentIndex)
break
}
}
}
window.addEventListener('scroll', handleScrollToc)
return () => {}
}, [headList])
基于滾動(dòng)距離和元素到頂部的距離來(lái)判斷
這里我們利用到dom元素的offsetTop屬性,計(jì)算目標(biāo)元素到父元素頂部的的距離.
因?yàn)閛ffsetTop只是到父元素頂部的距離,而不一定等于到頁(yè)面頂部的距離,我們可以用下面的方式把所有父元素的offsetTop相加,這樣就能得到到頁(yè)面頂部的距離
export function getElementToPageTop(el: any): number {
if (el.parentElement) {
return getElementToPageTop(el.parentElement) + el.offsetTop
}
return el.offsetTop
}
window的pageYoffset屬性可以計(jì)算當(dāng)滾動(dòng)條滾動(dòng)時(shí)document卷起的高度,也就等于scrollY吧.
我們考慮到兩種邊界情況,這樣邏輯比較清晰.
首先是指定的元素頂部和瀏覽器可視區(qū)域的下邊界重合的情況.
此時(shí)有等式
el到頁(yè)面頂部的距離= window.innerHeight+window.scrollY
el到頁(yè)面頂部的距離和window.innerHeight這兩個(gè)參數(shù)是固定的
我們繼續(xù)往下滾,那么window.scrollY就會(huì)增大,所以有
window.scrollY> el到頁(yè)面頂部的距離 - window.innerHeight
繼續(xù)滾動(dòng)直到目標(biāo)元素的下邊界和瀏覽器的上邊界重合,此時(shí)是元素離開(kāi)可視窗口的情況.
此時(shí)同樣也有一個(gè)等式,并且隨著繼續(xù)向下滾動(dòng),等式變成不等式...
通過(guò)這兩個(gè)邊界條件,就可以確定dom元素在可視窗口區(qū)域的區(qū)間.
方法二的瀏覽器兼容性不如方法一.所以一般用第一種.