상세 컨텐츠

본문 제목

[JS] Intersection Observer API의 사용법과 활용방법(코드 있음)

WEB-Front end/*JAVASCRIPT

by 주초위왕 2024. 2. 15. 17:15

본문

바닐라 자바스크립트로 좌표값을 찍어서 효과를 주려고 할 때마다 효과를 주려는 높이를 콘솔로 찍어서 높이를 재는게 너무 불편해서 Intersection Observer API를 활용하여 편하게 구현하였다.

 

아래 코드를 보면 효과를 주고싶은 높이와 윈도우의 자표를 찍어 번거롭게 구현을 하였는데 Intersection Observer API를 쓰면 더 쉽게 효과를 줄 수 있다.

const header = document.querySelector('.header');
const headerHeight = header.getBoundingClientRect().height;	// getBoundingClientRect 높이를 반환해주는 함수임

document.addEventListener('scroll', () => {		// 화살표 함수
	if(window.scrollY > headerHeight) {
		header.classList.add('header--dark');
	} else {
		header.classList.remove('header--dark');
	}
});

 


<div id="container">
  <div class="content">One</div>
  <div class="content">Two</div>
  <div class="content">Three</div>
  <div class="content">Four</div>
  <div class="content">five</div>
  <div class="content">sixe</div>
</div>
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

#container {
  display: flex;
  flex-direction: column;
}

.content {
  background-color:black;
  width: 100px;
  height: 100px;
  margin: 10px;
  opacity: -1;
  transition: opacity 0.5s;
}

.content--change {
  background: red;
	box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
  opacity: 3;
}

https://baeharam.netlify.app/posts/javascript/intersection-observer

 

[JS] Intersection Observer 사용법 - 배하람의 블로그

스크롤에 따른 효과를 어떻게 줄 수 있을까? 웹 개발을 하다보면 사용자가 스크롤 하는 상태에 따라서 현재 보여지는 뷰포트에 가시적으로 어떤 엘리먼트가 나타나는지 확인하고 싶을 때가 있

baeharam.netlify.app

 

// 구현 계획
// 1. 모든 섹션 요소들과 메뉴 아이템들을 가지고 온다.
// 2. IntersectionObserver를 사용해서 모든 섹션들을 관찰해야 한다.
// 3. 보여지는 섹션에 해당하는 내용 아이템을 활성화 시킨다.
// 보여지는 섹션: 다수의 섹션이 동시에 보여진다면, 가장 첫번째 섹션을 선택

// #기본 동작 구현
const sectionIds = ['#home','#about','#skills','#work','#contact',];
const sections = sectionIds.map((id) => document.querySelector(id));
const navItems = sectionIds.map((id) => document.querySelector(`[href="${id}"]`));
      //  (id)화살표 함수는 가로 안에 넣어야함 아니면 타입 에러가 뜸

const visibleSelections = sectionIds.map(() => false);
let activeNavItem = navItems[0];

const options = {
    threshold: [0, 0.25, 0.5],
    rootMargin: '-200px 0px 0px 0px',
    threshold: [0, 0.98],
};


const observer = new IntersectionObserver(observerCallback, options);
sections.forEach((section) => observer.observe(section));

function observerCallback(entries) {
    let selectLastOne;  // flag 변수
    entries.forEach((entry) =>  {
        const index = sectionIds.indexOf(`#${entry.target.id}`);
        visibleSelections[index] = entry.isIntersecting;
        selectLastOne = 
        index === sectionIds.length - 1 &&
        entry.isIntersecting && 
        entry.intersectionRatio >= 0.95;
    });

    const navIndex = selectLastOne 
    ? sectionIds.length - 1 
    : findFirstIntersecting(visibleSelections);
  selectNavItem(navIndex);
}

function findFirstIntersecting(intersections) {
    const index = intersections.indexOf(true);
    return index >= 0 ? index : 0;
}

function selectNavItem(index) {
    const navItem = navItems[index];
    if (!navItem) return;
    activeNavItem.classList.remove('active');
    activeNavItem = navItem;
    activeNavItem.classList.add('active');

}
반응형

관련글 더보기

댓글 영역