Programming Language/🟨 Javascript

Intersection Observer를 활용한 이미지 동적 로딩

DarrenKwonDev 2021. 2. 8. 09:06

다른 포스트에서 옵저저 패턴 ~ Reactive Programming 패러다임 ~  RxJS으로 연결되는 프로그래밍 패러다임을 살펴본 바 있습니다. 여기서는 Intersection Observer(줄여서 io)를 활용하여 이미지를 동적으로 로딩해는 기능을 만들어보고자 합니다. 왜냐하면 Fuze에서 모델들의 사진을 뿌릴 때 이미지를 동적으로 로딩시켜야할 필요가 있기 때문입니다.

 

intersection Observer는 또 뭐야

특정 DOM 객체가 우리가 보는 화면 영역(viewport)과 겹치는 교차 이벤트를 감시합니다. 

쉬운 말로, dom이 우리가 보는 스크린에 노출이 되었냐? 아니냐?를 감지하는 겁니다.

기존에 scroll 이벤트를 감지하여 하용하는 방식은 스크롤이 내려가면 계속 트리거되기 때문에 성능에 문제를 일으킬 수도 있습니다. 

 

 

MDN에서 Intersection Observer API 를 사용하기에 적절한 예로 다음을 들어 준다.

 

  • 페이지가 스크롤 되는 도중에 발생하는 이미지나 다른 컨텐츠의 지연 로딩.(Lazy Loading) => 레진 코믹스에서도 사용한다고 한다!
  • 스크롤 시에, 더 많은 컨텐츠가 로드 및 렌더링되어 사용자가 페이지를 이동하지 않아도 되게 하는 infinite-scroll 을 구현.
  • 광고 수익을 계산하기 위한 용도로 광고의 가시성 보고. (광고 배너가 보일 때 카운트하기)
  • 사용자에게 결과가 표시되는 여부에 따라 작업이나 애니메이션을 수행할 지 여부를 결정. (보일 때 애니메이션 적용하기) => Wow.js를 사용해보셨다면, 유남생?

 

기본적인 Intersection observer 사용법과 이미지 동적 로딩

 

간단합니다. intersection observer 객체를 생성한 후, 가시 영역에 들어왔을 때 실행할 로직과, 실행후 관찰을 풀어내는 콜백 함수를 작성한 후, DOM에 io 객체를 observe 하면 됩니다.

 

대략 아래처럼 생겼습니다.

const observer = new IntersectionObserver(callback, options);

options 객체에 줄 수 있는 값들은 딱 3가지 값들이 있습니다.

대부분 경우에는 threshold 정도만 사용합니다.

 

- root는 관찰 영역의 기준을 설정합니다. 기본값은 브라우저 뷰포트가 됩니다. 여러분이 div 내부에 overflow: auto 등으로 스크롤을 생성한다면 root를 사용해볼 경험이 있을 겁니다.

 

http://blog.hyeyoonjung.com/2019/01/09/intersectionobserver-tutorial/

 

- rootMargin은 루트 영역의 마진을 결정합니다. css margin이랑 같은데, 좀더 가시성 영역을 세밀하게 다루기 위해서 사용합니다.

 

http://blog.hyeyoonjung.com/2019/01/09/intersectionobserver-tutorial/

 

 

- threshold는 DOM이 어느 정도로 노출되어야 트리거되는지 결정합니다. 1이면 완전히 노출되어야 콜백을 트리거하고, 0.2정도로 하면 위에 빼꼼 20% 정도 노출되면 트리거 합니다. 개인적인 취향으로는, io를 쓴 티를 팍팍 내기 위해서 0.7 정도로 설정합니다.

 

 

실제 코드

구체적 예시를 살펴봅시다., option은 threshold만 주었습니다.

<body>
    <div class="title">이미지 동적 로딩</div>
    <div class="desc">스크롤을 쭉 내려보세요</div>

    <div class="item-box">
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
    </div>
    <script src="index.js"></script>
</body>
// IntersectionObserver 객체 생성
const io = new IntersectionObserver((entries, observer) => {
  entries.forEach((entry) => {
    // 보이지 않으면 아무 동작도 하지 않음
    if (!entry.isIntersecting) {
      return;
    }

    const { target } = entry;
    target.style.backgroundImage = "url(https://placekitten.com/200/300)";

    console.log(`dynamic image loaded!`);

    // 가시성 관찰 풀기
    observer.unobserve(target);
  });
});

Array.from(document.querySelectorAll(".item-box div")).forEach((box) => {
  // observe 시작
  io.observe(box);
});

 

 

참고한 문서들)

http://blog.hyeyoonjung.com/2019/01/09/intersectionobserver-tutorial/

https://tech.lezhin.com/2017/07/13/intersectionobserver-overview