js監(jiān)聽元素是否出現(xiàn)在可視區(qū)域詳解(IntersectionObserver)
觀察者模式監(jiān)聽判斷dom元素是否在可視區(qū)域內(nèi)
本項(xiàng)目是使用vue3的寫法。
1.IntersectionObserver
IntersectionObserver
可以用來自動監(jiān)聽元素是否進(jìn)入了設(shè)備的可視區(qū)域之內(nèi),而不需要頻繁的計(jì)算來做這個(gè)判斷。由于可見(visible)的本質(zhì)是,目標(biāo)元素與視口產(chǎn)生一個(gè)交叉區(qū),所以這個(gè) API 叫做"交叉觀察器"
const observer = new IntersectionObserver(callback, option);
IntersectionObserver
是瀏覽器原生提供的構(gòu)造函數(shù),接受兩個(gè)參數(shù):
- callback:可見性發(fā)現(xiàn)變化時(shí)的回調(diào)函數(shù)
- option:配置對象(可選)。
構(gòu)造函數(shù)的返回值是一個(gè)觀察器實(shí)例。實(shí)例一共有4個(gè)方法:
- observe:開始監(jiān)聽特定元素
- unobserve:停止監(jiān)聽特定元素
- disconnect:關(guān)閉監(jiān)聽工作
- takeRecords:返回所有觀察目標(biāo)的對象數(shù)組
1.1 observe 方法
該方法需要接收一個(gè)target
參數(shù),值是Element
類型,用來指定被監(jiān)聽的目標(biāo)元素
// 獲取元素 const target = document.getElementById("dom"); // 開始觀察 io.observe(target);
1.2 unobserve 方法
該方法需要接收一個(gè)target
參數(shù),值是Element
類型,用來指定停止監(jiān)聽的目標(biāo)元素
// 獲取元素 const target = document.getElementById("dom"); // 停止觀察 io.unobserve(target);
1.3 disconnect 方法
該方法不需要接收參數(shù),用來關(guān)閉觀察器
// 關(guān)閉觀察器 io.disconnect();
// 頁面加載時(shí)監(jiān)聽元素 onMounted(() => { var demo3 = document.querySelector('document.querySelector(dom)) // 獲取元素 var observer = new IntersectionObserver((mutaions)=>{ // 創(chuàng)建IntersectionObserver對象 console.log(mutaions[0].isIntersecting) }) observer.observe(demo3) // 需要監(jiān)聽的元素 }
1.4 takeRecords 方法
該方法不需要接收參數(shù),返回所有被觀察的對象,返回值是一個(gè)數(shù)組
// 獲取被觀察元素 const observerList = io.takeRecords();
1.5 callback 參數(shù)
目標(biāo)元素的可見性變化時(shí),就會調(diào)用觀察器的回調(diào)函數(shù)callback。
callback一般會觸發(fā)兩次。一次是目標(biāo)元素剛剛進(jìn)入視口,另一次是完全離開視口。
const io = new IntersectionObserver((changes, observer) => { console.log(changes); console.log(observer); });
1.6 options
threshold:
決定了什么時(shí)候觸發(fā)回調(diào)函數(shù)。它是一個(gè)數(shù)組,每個(gè)成員都是一個(gè)門檻值,默認(rèn)為[0],即交叉比例(intersectionRatio)達(dá)到0時(shí)觸發(fā)回調(diào)函數(shù)。用戶可以自定義這個(gè)數(shù)組。比如,[0, 0.25, 0.5, 0.75, 1]就表示當(dāng)目標(biāo)元素 0%、25%、50%、75%、100% 可見時(shí),會觸發(fā)回調(diào)函數(shù)。root
: 用于觀察的根元素,默認(rèn)是瀏覽器的視口,也可以指定具體元素,指定元素的時(shí)候用于觀察的元素必須是指定元素的子元素rootMargin
: 用來擴(kuò)大或者縮小視窗的的大小,使用css的定義方法,10px 10px 30px 20px表示top、right、bottom 和 left的值
2. IntersectionObserverEntry 對象
changes數(shù)組中的每一項(xiàng)都是一個(gè)IntersectionObserverEntry 對象
boundingClientRect
:目標(biāo)元素的矩形區(qū)域的信息- i
ntersectionRatio
:目標(biāo)元素的可見比例,即intersectionRect占
boundingClientRect的比例,完全可見時(shí)為1,完全不可見時(shí)小于等于0 intersectionRect
:目標(biāo)元素與視口(或根元素)的交叉區(qū)域的信息isIntersecting
: 布爾值,目標(biāo)元素與交集觀察者的根節(jié)點(diǎn)是否相交(常用)isVisible
: 布爾值,目標(biāo)元素是否可見(該屬性還在試驗(yàn)階段,不建議在生產(chǎn)環(huán)境中使用)rootBounds
:根元素的矩形區(qū)域的信息,getBoundingClientRect()方法的返回值,如果沒有根元素(即直接相對于視口滾動),則返回nulltarget
:被觀察的目標(biāo)元素,是一個(gè) DOM 節(jié)點(diǎn)對象(常用)time
:可見性發(fā)生變化的時(shí)間,是一個(gè)高精度時(shí)間戳,單位為毫秒
3. 是否在可視區(qū)域
onMounted(() => { var observer = new IntersectionObserver((entries) => { console.log(111111, entries[0].isIntersecting); dataMap.showMyBox = !entries[0].isIntersecting; //返回true代表在頁面可視區(qū)域,false代表不在頁面可視區(qū)域。 }); observer.observe(document.querySelector(dom)); }
// 頁面卸載時(shí)可解綁 onBeforeUnmount(() => { if (observer) { observer.unobserve(document.querySelector(dom)); //解綁元素 observer.disconnect(); //停止監(jiān)聽 } });
4. 圖片懶加載
使用 IntersectionObserver 非常容易實(shí)現(xiàn)圖片懶加載,首先需要觀察懶加載元素,然后等元素進(jìn)入可視區(qū)域后設(shè)置圖片 src;同時(shí),還可以結(jié)合 IntersectionObserver.rootMargin
實(shí)現(xiàn)提前加載圖片,一般可以設(shè)置為 1~2 倍瀏覽器窗口的視口高度,優(yōu)化用戶體驗(yàn)
/** * @method lazyLoad * @param {NodeList} $imgList 圖片元素集合 * @param {number} preloadHeight 預(yù)加載高度 */ export function lazyLoad($imgList, preloadHeight = 1000) { const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { // 目標(biāo)元素出現(xiàn)在 root 可視區(qū),返回 true const $target = entry.target const src = $target.getAttribute('lazyload') if (src) { $target.setAttribute('src', src) // 真正加載圖片 } observer.unobserve($target) // 解除觀察 } }) }, { rootMargin: `0px 0px ${preloadHeight}px 0px`, }) Array.prototype.forEach.call($imgList, ($item) => { if ($item.getAttribute('src')) return // 過濾已經(jīng)加載過的圖片 observer.observe($item) // 開始觀察 }) }
使用方法:
// 圖片元素設(shè)置 lazyload 屬性 <img lazyload="圖片鏈接" alt="圖片說明"> // 觀察圖片元素 lazyLoad(document.querySelectorAll("[lazyload]"))
5. 元素吸頂、吸底
如果頁面結(jié)構(gòu)比較簡單可以直接使用 css 粘性布局。
IntersectionObserver 實(shí)現(xiàn)元素固定思路也很簡單,首先需要給固定元素包一層父元素,父元素指定高度占位,防止固定元素吸附時(shí)頁面抖動,然后觀察父元素的可視狀態(tài)變化,當(dāng)父元素即將離開可視區(qū)域時(shí)改變固定元素的樣式。
/** * @method fixBanner * @param {HTMLElement} $observeEle 觀察元素 * @param {HTMLElement} $fixEle 固定定位元素 */ export function fixBanner($observeEle, $fixEle) { const $ele = $fixEle const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { $ele.style.cssText = '' } else { $ele.style.cssText = 'position: fixed; top: 0; left: 0' } }) }, { threshold: 1, // threshold 設(shè)置為 1 表示目標(biāo)元素完全可見時(shí)觸發(fā)回調(diào)函數(shù) }) observer.observe($observeEle) // 開始觀察 }
6. 加載更多
IntersectionObserver 實(shí)現(xiàn)加載更多需要在列表后面增加一個(gè)尾部元素(比如加載更多動畫),當(dāng)尾部元素進(jìn)入可視區(qū)域就加載更多數(shù)據(jù),注意尾部元素一定要一直處于所有列表元素的后面。
提前加載高度不能隨意設(shè)置,如果設(shè)置太大會導(dǎo)致尾部元素一直處于可視狀態(tài)。
function loadMore() { const observer = new IntersectionObserver( (entries) => { const loadingEntry = entries[0] if (loadingEntry.isIntersecting) { // 請求數(shù)據(jù)并插入列表 } }, { rootMargin: '0px 0px 600px 0px', // 提前加載高度 }, ) observer.observe(document.querySelector('.mod_loading')) // 觀察尾部元素 }
總結(jié)
到此這篇關(guān)于js監(jiān)聽元素是否出現(xiàn)在可視區(qū)域(IntersectionObserver)的文章就介紹到這了,更多相關(guān)js監(jiān)聽元素出現(xiàn)可視區(qū)域內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
CSS+JS實(shí)現(xiàn)點(diǎn)擊文字彈出定時(shí)自動關(guān)閉DIV層菜單的方法
這篇文章主要介紹了CSS+JS實(shí)現(xiàn)點(diǎn)擊文字彈出定時(shí)自動關(guān)閉DIV層菜單的方法,設(shè)計(jì)javascript操作菜單的彈出與關(guān)閉的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-05-05原生JS實(shí)現(xiàn)仿淘寶網(wǎng)左側(cè)商品分類菜單效果代碼
這篇文章主要介紹了原生JS實(shí)現(xiàn)仿淘寶網(wǎng)左側(cè)商品分類菜單效果代碼,可實(shí)現(xiàn)簡單的鼠標(biāo)滑過tab切換的功能,非常簡單實(shí)用,需要的朋友可以參考下2015-09-09javascript之大字符串的連接的StringBuffer 類
javascript之大字符串的連接的StringBuffer 類...2007-05-05javascript觀察者模式實(shí)現(xiàn)自動刷新效果
這篇文章主要為大家詳細(xì)介紹了javascript觀察者模式實(shí)現(xiàn)自動刷新效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09javascript自動生成包含數(shù)字與字符的隨機(jī)字符串
這篇文章主要介紹了javascript自動生成包含數(shù)字與字符的隨機(jī)字符串,涉及Math.random()和Math.floor()兩個(gè)函數(shù)的使用技巧,需要的朋友可以參考下2015-02-02javascript實(shí)現(xiàn)省市區(qū)三級聯(lián)動下拉框菜單
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)省市區(qū)三級聯(lián)動下拉框菜單很詳細(xì)的代碼,解決了大家實(shí)現(xiàn)javascript省市區(qū)三級聯(lián)動下拉框菜單的問題,感興趣的小伙伴們可以參考一下2015-11-11