본문 바로가기
JS

Intersetion Observer API

by kicksky 2021. 3. 1.

타겟 요소와 상위 요소( or document viewport ) 사이의 intersection 내의 변화를 비동기적으로 관찰하는 방법.

요소의 가시성, 두 요소의 상대적인 가시성을 탐지하는 일

 

필요성

- 페이지 스크롤할 때, 컨텐츠를 지연로딩으로 불러오게 하기 위해

- 페이지를 스크롤할 때, 더 많은 컨텐츠 로드 및 렌더링 ( 페이지네이션 )

- 광고 수익 계산

- 사용자에게 보일 때만 발생하는 작업들

 

page scroll은 모든 요소가 메인 스레드에서 실행되기 때문에 성능 문제 발생 가능성 농후

 

IO API

- 감시 요소가 다른 요소에 들어가거나 나갈 때, 겹치는 부분이 변경될 때 콜백 함수가 실행된다.

- 사이트는 요소 교차를 지켜보기 위해 메인 스레드 사용할 필요 X. 비동기로 실행.

메소드

IntersectionObserver.observe( tE )
IntersectionObserver.unobserve( tE )

IntersectionObserver.disconnect( tE )

컨셉 및 사용

1) target이 root(기기 뷰포트나 특정 요소)와 교차

2) observer가 target을 감지할 때마다 콜백 호출

 

생성

let options = {
  root: document.querySelector('#scrollArea'), //
  rootMargin: '0px', //
  threshold: 1.0 // target이 root에서 얼마나 보여질 것인지
}

let observer = new IntersectionObserver(callback, options);

 

타겟팅

let target = document.querySelector('#listItem');
observer.observe(target);

콜백함수가 처음으로 실행

이제 타겟이 IO의 threshold 만날 때마다 콜백 호출하고, 콜백은 Entry 객체 리스트를 받는다

 

콜백함수

let callback = (entries, observer) => {
  entries.forEach(entry => {
    // Each entry describes an intersection change for one observed
    // target element:
    //   entry.boundingClientRect
    //   entry.intersectionRatio
    if (entry.intersectionRatio > 0) {
      entry.target.classList.add('tada');
    }
    // 그 외의 경우 'tada' 클래스 제거
    else {
      entry.target.classList.remove('tada');
    }
    //   entry.intersectionRect
    //   entry.isIntersecting
    //   entry.rootBounds
    //   entry.target
    //   entry.time
  });
};

메인 스레드에서 실행. 따라서 가능한 빠르게 실행되어야 함.

 

Andres Gallo, Lazy Load Images with Vanilla JavaScript and Intersection Observer

const images = document.querySelectorAll("img");

const imgOptions = {};
const imgObserver = new IntersectionObserver((entries, imgObserver) => {
  entries.forEach((entry) => {
    if (!entry.isIntersecting) return; // 어떤 이벤트 X

    const img = entry.target;
    img.src = img.src.replace("w=10&", "w=800&");
    imgObserver.unobserve(entry.target); // 이미 받은 이미지는 다시 fetch 하지 않도록
  });
  
  혹은
  
  entries.forEach((entry) => {
        if(entry.isIntersecting) {
            const lazyImage = entry.target
            lazyImage.src = lazyImage.dataset.src // dataset의 src를 src로
        }
    })
    
}, imgOptions);

// observe 달기
images.forEach((img) => { 
  imgObserver.observe(img); 
});

 


 

'JS' 카테고리의 다른 글

배열 Array: 루프  (0) 2021.03.08
중첩된 async await  (0) 2021.03.08
Fetch API  (0) 2021.03.05
Array-like objects, NodeList, HTMLCollection  (0) 2021.03.04
배열 Array: 아이템 추가 및 삭제, flat( )  (0) 2021.03.03

댓글