懶加載IntersectionObserver 深入理解


IntersectionObserver

callback

var observer = new IntersectionObserver(callback,options);
callback 監聽元素的可見性
options   配置參數

callback 一般會觸發兩次,一次是目標進入視口(可見),另一次是完全離開(不可見)

  let observer = new IntersectionObserver(changes => {
    changes.forEach(change => {
      // 完全可見時為1,完全不可見時小於等於0
      console.log(change.intersectionRatio);

      // 被觀察的目標元素,是一個 DOM 節點對象
      // 當前可視區域正在變化的元素
      console.log(change.target);

    })
  })
  如果沒設置Option 就只觸發兩次

每一個屬性的含義

time:可見性發生變化的時間,是一個高精度時間戳,單位為毫秒

target:被觀察的目標元素,是一個 DOM 節點對象

rootBounds:根元素的矩形區域的信息,getBoundingClientRect()方法的返回值,如果沒有根元素(即直接相對於視口滾動),則返回null

boundingClientRect:目標元素的矩形區域的信息

intersectionRect:目標元素與視口(或根元素)的交叉區域的信息

intersectionRatio:目標元素的可見比例,即intersectionRect占boundingClientRect的比例,完全可見時為1,完全不可見時小於等於0

    time: 3893.92
  🔽rootBounds: ClientRect
      bottom: 920
      height: 1024
      left: 0
      right: 1024
      top: 0
      width: 920

option

threshold 屬性

threshold 屬性決定了什么時候觸發回調函數

new IntersectionObserver(
  entries => {/* ... */}, 
  {
    threshold: [0, 0.25, 0.5, 0.75, 1]
  }
);

比如,[0, 0.25, 0.5, 0.75, 1]就表示當目標元素 0%、25%、50%、75%、100% 可見時,會觸發回調函數。

root屬性 rootMargin屬性

root屬性指定目標的容器節點(根元素)

屬性 說明
root 監聽元素的祖先元素 Element 對象
rootMargin 一個在計算交叉值時添加至根的邊界盒(bounding_box)中的一組偏移量,類型為字符串,可以有效的縮小或擴大根的判定范圍從而滿足計算需要。語法大致和 CSS 中的 margin 屬性等同,默認值是"0px 0px 0px 0px"
top、right、bottomleft
單位: “px”,”%
threshold 規定了一個監聽目標與邊界盒交叉區域的比例值,可以是一個具體的數值或是一組 0.0 到 1.0 之間的數組。若指定值為 0.0,則意味着監聽元素即使與根有 1 像素交叉,此元素也會被視為可見.
{
  root: Element,
  rootMargin: string,
  threshold: number | number[]
}

默認

{
  root: null,
  rootMargin: "0px 0px 0px 0px",
  threshold: [0]
}

使用

方法 說明
disconnect() 使 IntersectionObserver 對象停止監聽工作。
observe() 使 IntersectionObserver 開始監聽一個目標元素。
unobserve() 使 IntersectionObserver 停止監聽特定目標元素。

IntersectionObserver使用的是異步的方式,可以不用擔心性能問題

  1. 開始觀察某個獵物:observer.observe(el)
  2. 取消觀察某個獵物:observer.unobserve(el)
  3. 自爆,關掉這個觀察器:observer.disconnect()

可見性demo

const target = document.getElementById('target')

const observer = new IntersectionObserver((entries) => {
  const [entry] = entries

  if (entry.isIntersecting) {
    console.log('元素曝光了')
  }
})

observer.observe(target)

懶加載

為了惰性加載圖片,當然不能把 img 的 src 直接設置成圖片地址,不然瀏覽器直接就顯示了。而一般是放在data-src屬性中,或增加lazy-load類。

<img data-src="https://example.com/me.png" width="100px" height="50px" />
    
找到所有需要惰性加載的圖片
var images = document.querySelectorAll('img[data-src]');
var observer = new IntersectionObserver(onIntersection);
images.forEach(img => { observer.observe(img); });
 const target = document.getElementById('ccc')

  const observer = new IntersectionObserver((entries) => {
    const [entry] = entries

    if (entry.isIntersecting) {
      entry.target.src='xxxx';
      // 取消監控
       observer.unobserve(entry.target)
    }
  })

  observer.observe(target)

當獵物進入到鏡頭后,isIntersecting會是true,不在鏡頭內就是false。

解釋

  • intersectionRatio 相交比例。剛開始相交是0%,相交一半是50%,完全進入則是100%
  • isIntersecting 是否正在相交。intersectionRatio != 0 即正在相交。(后來增加的屬性)
  • target 被觀察的元素。
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if(entry.isIntersecting) {
        console.log("元素相交");
      } else {
        console.log("元素不相交");
      }
    });
  });

root 的理解

<div style="height:400px;overflow-y:scroll">
  <div style="height:200vh;background-color: khaki;"></div>
  <div id="ccc" style="height:500px;background-color: #b1ff6d;"></div>
  <div style="height:200vh;background-color: khaki;"></div>
</div>

  const target = document.getElementById('ccc')

  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        console.log("元素相交");
      } else {
        console.log("元素不相交");
      }
    });
  }, {
    root: document.querySelector('#aaa'),
  });

  observer.observe(target)

rootMargin

<div style="height:200vh;background-color: #f00d0d;"></div>
<div style="height:400px;overflow-y:scroll;" class="aaa">
  <div id="ccc" style="height:500px;background-color: #b1ff6d;"></div>
  <div style="height:200vh;background-color: khaki;"></div>
</div>

 const target = document.getElementById('ccc')
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        console.log("元素相交");
      } else {
        console.log("元素不相交");
      }
    });
  }, {
    root: document.querySelector('#aaa'),
    rootMargin:'50%'     //根 400px  50% 是200px
    /* 距離下面200px的時候相交*/
    /* 距離下面200px的時候不相交*/
  });
  observer.observe(target)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM