Intersection Observer API

seul_velog·2022년 1월 12일
0

JS note

목록 보기
6/9
post-thumbnail
post-custom-banner

Intersection observer

기본적으로 브라우저 뷰포트(Viewport)와 설정한 요소(Element)의 교차점을 관찰하며, 요소가 뷰포트에 포함되는지 포함되지 않는지, 사용자 화면에 현재 보이는 요소인지 아닌지를 구별하는 기능을 제공한다.

  • 이 기능은 비동기적으로 실행되기 때문에, scroll 같은 이벤트 기반의 요소 관찰에서 발생하는 렌더링 성능이나 이벤트 연속 호출과 같은 문제 없이 사용 가능하다.

  • new IntersectionObserver()를 통해 생성한 인스턴스(io)로 관찰자(Observer)를 초기화하고 관찰할 대상(Element)을 지정한다.
  • 생성자는 2개의 인수(callback, options)를 가진다.
// ex.)
// ▼ 관찰자 초기화
const io = new IntersectionObserver(callback, options)

// ▼ 관찰할 대상(요소) 등록
io.observe(element) 



callback

  • 관찰할 대상(Target)이 등록되거나 가시성(Visibility, 보이는지 보이지 않는지)에 변화가 생기면 관찰자는 콜백(Callback)을 실행한다.
  • 콜백은 2개의 인수(entries, observer)를 가진다.
// ex.)
const io = new IntersectionObserver((entries, observer) => {}, options)
io.observe(element)

entries

  • entries는 IntersectionObserverEntry 인스턴스의 배열이다.

  • IntersectionObserverEntry는 읽기 전용(Read only)의 다음 속성들을 포함한다. ▼

  • boundingClientRect: 관찰 대상의 사각형 정보(DOMRectReadOnly)
    → 포지션과 너비와 높이를 알 수 있다. 요소가 윈도우 창에 벗어나서 그려져있는 경우 x좌표는 0이지만, y좌표는 브라우저에서의 좌표 0.0 밖으로 넘어가 있기때문에 - 이다.

  • intersectionRect: 관찰 대상의 교차한 영역 정보(DOMRectReadOnly)
    → 얼마만큼 들어와 있는지 확인 할 수 있다. 0부터 1까지로 표현된다. (안에 전부 다 들어와 있다면 1 , 70%만 들어와 있다면 0.7)

  • intersectionRatio: 관찰 대상의 교차한 영역 백분율(intersectionRect 영역에서 boundingClientRect 영역까지 비율, Number)
    → 들어온 포지션과 크기가 들어있는 인터섹션이다.

  • isIntersecting: 관찰 대상의 교차 상태(Boolean)
    → 요소가 안으로 들어오는 상태라면 true, 윈도우에서 밖으로 나가는 상태라면 false가 된다.

  • rootBounds: 지정한 루트 요소의 사각형 정보(DOMRectReadOnly)
    → 아무것도 지정하지 않으면 (뷰포트 기준으로) 현재 보여지고 있는 윈도우창을 말한다.

  • target: 관찰 대상 요소(Element)

  • time: 변경이 발생한 시간 정보(DOMHighResTimeStamp)


observer

  • 콜백이 실행되는 해당 인스턴스를 참조한다.
const io = new IntersectionObserver((entries, observer) => {
  console.log(observer)
}, options)

io.observe(element)



option

root

  • root : 설정하지 않으면 항상 null로 되어져 있다.
    → 따로 루트를 명시하지 않으면 뷰포트가 기본이다. (뷰포트: 우리가 보는 윈도우 부분)
    → 어떤 걸 기준으로 요소들이 들어오고 나가는지를 확인하고 싶을 때는, 부모 컨테이너를 지정해 줄 수 있다.

  • rootMargin : 바깥 여백(Margin)을 이용해 Root 범위를 확장하거나 축소할 수 있다.
    → 설정하지 않으면 항상 0픽셀로 되어져 있다.
    → 뷰포트가 있다고 가정하면 그 바깥으로 (윈도우에서 우리가 보이지않는 바깥부분) 지정한 값만큼 마진을 줘서, 마진까지 더 포함된 영역으로 계산하고자 할때 쓰인다.
    → 정해진 부모 컨테이너 이후부터 무언가를 미리 준비해 놓을 수 있다. (화면에 근접할 경우 미리 컨텐츠를 준비해놓을 때 유용하게 쓰임)
    → CSS의 margin과 같이 4단계로 여백을 설정할 수 있으며, px 또는 %로 나타낼 수 있다. 기본값은 0px 0px 0px 0px이며 단위를 꼭 입력해야 한다.

  • threshold : 얼마만큼 보여져야 콜백함수가 호출될지를 결정한다.
    → 기본값은 0이다. 즉, 1px만 보여도 콜백함수가 실행된다.
    → 전체 들어왔을 때 실행하고 싶으면 1로 설정, 0.5는 50%만 들어왔을 때 실행하게 된다.
    → 나갈 때는 (= isIntersecting 이 false일 때) 지정된 값의 반대가 된다. 즉 1이면 0, 0.2면 0.8


Methods

  • observe() : 대상 요소의 관찰을 시작한다.
  • unobserve() : 대상 요소의 관찰을 중지한다.
  • disconnect() : IntersectionObserver 인스턴스가 관찰하는 모든 요소의 관찰을 중지한다.
  • takeRecords() : IntersectionObserverEntry 객체의 배열을 반환한다.





✍️ 코드를 작성해 가면서 이해하기

API 이해하기

 const callback = (entries, observer) => { // ③
        console.log("observe!");
      }
// 클래스의 생성자에 callback이라는 것을 전달해서, 새로운 observer라는 오브젝트를 만들었다
const observer = new IntersectionObserver(callback); // ②

const boxes = document.querySelectorAll(".box");  // ①    
boxes.forEach((box) => observer.observe(box)); // ④

1) boxes 라는 변수에 document.querySelectorAll 를 이용해서 만들어둔 박스리스트를 할당한다.
2) 웹API에서 제공하는 IntersecrionObserver 라는 클래스를 이용해서 → new연산자를 이용해서 오브젝트를 만든다. 이때 이 API는 콜백함수를 받는다.
3) 콜백함수를 정의한다. 그리고 이 콜백함수는 entriesobserver 를 인자로 받을 수 있다고 한다. 이렇게 만들어진 관찰자를 이용해서 관찰한다.
4) 각각의 박스를 관찰자가 관찰하도록 명령해 놓은 상태이다.

  • 함수를 호출할 때 click 이벤트에 핸들러를 등록해 놓으면, 이벤트라는 정보를 인자로 전달해 주는 것 처럼, 비슷한 원리로 여기에는 entriesobserver 라는 유용한 정보들을 전달해 준다고 이해했다.

  • 여기 들어가는 observe() 괄호 안에 어떤 대상이 들어가는지 궁금해서 MDN을 찾아보았다.
  • IntersectionObserver.observe(타겟요소)


entries, observer 이해하기

entriesobserver 를 각각 출력하면 이렇게 뜬다.

▼ 처음에는 20개의 모든 아이템이 윈도우에 들어왔기 때문에 20개의 요소가 들어있는 것을 볼 수 있다

▼ 각각의 배열에는 인터섹션옵저버엔트리 라는 오브젝트가 들어있는 것을 볼 수 있다.
IntersectionObserverEntry → 화면에 들어온 요소에 대한 정보를 담음

entries는 배열이다.

const callback = (entries, observer) => {
// 배열이라서 >> [0]과 같은 인덱스 번호를 매기지 않고 출력했더니, undefined가 출력되었다.
        console.log(entries[0].boundingClientRect); // [0]을 해주니 잘 출력!
      };

▼ 궁금해서 출력해 보았다. 이런식으로 원하는 정보를 지정, 여러가지를 알 수 있을 것 같았다.

const callback = (entries, observer) => {
        entries.forEach(entry1 => {
	console.log(entry1.boundingClientRect);
        })
      };

▼ 한번 출력해보자

  • 이렇게 출력하자마자 20개의 boundingClientRect 가 출력되는 것을 확인! 🤔
  • 위에서 출력한 것과는 다르게 forEach 작업을 해줌으로써, 각각의 배열요소마다 접근이 되기때문에 [0]과 같은 접근 없이 바로 boundingClientRect 에 접근 할 수 있었다.

▼ 요소가 들어오고 나가는 것을 확인해보자

const callback = (entries, observer) => {
        entries.forEach((entry1) => {
          console.log(entry1.target);
        });
      };

❓들어오는 것과 나가는 것에 대해서 처리를 다르게 하고 싶다면

  • if 문 사용해보기
  • isIntersecring : 요소가 안으로 들어오는 상태라면 true, 윈도우에 있다가 밖으로 나가는 상태라면 false가 된다.
const callback = (entries, observer) => {
        entries.forEach((entry1) => { 
          if (entry1.isIntersecting) { // 들어오면 true 니까 true
            console.log(entry1.target);
          } else {
            console.error(entry1.target); // 에러-> 빨간색으로 표시해서 구분해보기
          }
        });
      };


✍️ 이렇게 들어오면 그대로, 나가면 에러가 출력되는 걸 구분해서 확인해 볼 수 있었다. 즉, 이런 방식으로 들어오고 나간 것에 대해서 원하는 처리를 할 수도 있을 것이다. 😀





+) 추가

API 사용해보기

✍️ 네비게이션 바를 일정 스크롤 위치에서 부터 sticky로 전환해서 보여주기

1) scroll 이벤트를 사용할 경우

❗️ 스크롤 이벤트는 성능에 좋지않다.

const initialCoords = section1.getBoundingClientRect().top;
window.addEventListener('scroll', () => {
  if (window.scrollY > initialCoords) nav.classList.add('sticky');
  else nav.classList.remove('sticky');
});

2) Intersection Observer API로 리팩토링

const header = document.querySelector('.header');
const navHeight = nav.getBoundingClientRect().height;

const stickyNav = function (entries) {
  const [entry] = entries; // entries는 IntersectionObserverEntry 인스턴스의 배열
  console.log(entry);

  // isIntersecting : 관찰 대상의 교차 상태(Boolean)
  if (!entry.isIntersecting) nav.classList.add('sticky');
  else nav.classList.remove('sticky');
};

const headerObserver = new IntersectionObserver(stickyNav, {
  root: null, // 기본값 null -> 뷰포트가 기본
  threshold: 0, // 기본값 0 -> 얼마만큼 보여져야 콜백을 호출할지 결정
  rootMargin: `-${navHeight}px`, // 기본값 0px -> 마진을 이용해 Root 범위 확장 및 축소가능
});
headerObserver.observe(header);




reference
MDN - Intersection Observer API
MDN - IntersectionObserver.observe()
heropy - intersection _observer
dream-coding

profile
기억보단 기록을 ✨
post-custom-banner

0개의 댓글