March 11, 2021
프론트엔드 개발을 해오다보면 사용자의 스크롤에 따라 특정 조건을 감지해야하는 경우들이 정말 많다.
대표적으로
infinite scroll
dataSet
에 값을 갖고 있다가 조건이 되는 높이가 되었을 시,src
속성 부여하는lazy loading
위와 같은 경우, 대부분 수동으로 높이를 구해서 작업을 하였는데, 스크롤 이벤트 이후 실행되는 콜백메소드의 경우는 throttling
방식으로 끊어줄 수 있지만, 해당 이벤트 자체는 계속 감지되는지라 불필요한 소요가 존재하기도 했다.
그러던 중 해당 API
를 발견하였다.
MDN
의 말을 내 느낌대로 줄여본다면, target
이 되는 엘리먼트의 경계를 넘나들 때, 콜백함수가 실행되는것 같다.
// dom
<div class="div1 div"></div>
<div class="div2 div"></div>
// script
const options = {
root: null
rootMargin: "0px 0px 80px 0px",
threshold: 0,
};
const io = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.intersectionRatio > 0) {
// 모습을 드러냈으니, 원하는 로직 실행
console.log(entry.target, "활성화");
} else {
// 모습을 감춘상태
console.log(entry.target, "비활성화");
}
});
}, options);
const els = document.querySelectorAll(".div");
els.forEach(el => io.observe(el));
해당 생성자에 있어서 첫번째 인자로는 콜백함수, 두번째 인자로는 옵션을 보내줄 수 있다.
옵션의 속성으로는
root
: 지정해 주지 않으면 기본값으로, 감지를 할 범위를 의미하는것 같다. 기본값은 window
전체인듯 하다.rootMargin
: css
의 margin
과 같은 구조로, 감지를 하는 target
요소 + margin
값에 도달할 때, 콜백함수를 실행시킨다.threshold
: 0~1사이의 값으로 보여지는 %를 의미한다고하는데, 사실상 대부분 보여지자마자 실행시키도록 하니깐 0으로 두면 될듯..?콜백함수의 첫번째 변수에는 target
이 하나의 요소든 여러개의 요소든 배열의 구조인것 같다. 따라서, forEach
와 같은 순회 메소드로 관리하는것이 좋아보인다.
크게 신경쓸 속성으로는 target
과, intersectionRatio
가 있는것같다.
target
: 해당 API
에 영향을 받는 요소들intersectionRatio
: 해당 요소가 감지?되기위한 기준 으로 0보다 클경우 해당 요소가 조건에 해당되고, 0이면 해당되지 않는다.oberver
요소가 target
이 되고, 해당 요소가 화면에 보일때 새로운 div
를 추가해주는 방식이다.
unobserve
메소드를 통해, 첫번째 인자로 요소를 받으며, 요소에 대한 감지를 제거할 수 있다.
disconnect
메소드는 unobserve
랑 비슷한 것 같은데, 아무런 요소도 받지 않는것 보아 전부를 해제하는 느낌이다.
// dom
<div class="divWrap">
<div class="div1 div"></div>
</div>
<div class="observer"></div>
// script
let options = {
rootMargin: "0px 0px 0px 0px",
threshold: 0,
};
const divWrap = document.querySelector(".divWrap");
const callback = entries => {
entries.forEach((entry, index) => {
if (entry.intersectionRatio > 0) {
divWrap.innerHTML += `<div class="div${index + 2} div"></div>`;
}
});
};
let observer = new IntersectionObserver(callback, options);
const target = document.querySelector(".observer");
observer.observe(target);
// observer.unobserve(target);
// observer.disconnect();
감지 중단을 위해 unobserve
를 사용한 다음, observe
를 다시 호출해주게 될 경우, 스크롤이 끝에 가있을 때 무한히 호출된다.
당연한것이,
observe
상태일 때 대상이 지정한 비율만큼 보일 때 한번 실행되는데, 대상이 보이는 상태에서unobserve
시켰다가 다시observe
하게 되면 실행되었다는 기록이 초기화된 상태이기 때문에 또 한번 실행되게되어 무한반복.
scroll
이벤트의 경우 어쩔수없이 꾸준히 발생하고, 이후에 높이를 각각 계산하여야 했었는데, 모든것을 한번에 처리해주니 참 좋은듯 하다.
사용자가 스크롤을 사용할 때, 모든 스크롤을 감지하고 이벤트를 호출하게 되면서 발생하는 성능문제에 대해 throttling
을 사용하는것이 권장되었지만, 특정 지점에 도달할 때 만 호출되도록 도와주는점이 큰 매력!
단, 비동기로 서버에 데이터를 요청하는것과는 별개인듯 하여 그 작업에 대해서는 별도의 성능개선작업을 해줘야 할 듯