[JS ] ๐ญ Intersection Observer API ์์๋ณด๊ธฐ
๐ญ Intersection Observer API ๋?
Intersection Observer API(๊ต์ฐจ ๊ด์์) ๋ ํ์ผ ์์๊ฐ ํ๋ฉด์ ๋ณด์ด์ง๋์ง ์ฌ๋ถ๋ฅผ ๊ด์ฐฐํ๋ API ์ด๋ค.
React๋ก Infinite Scroll ๊ตฌํ์ ์ํด ํ๋ฌ๊ทธ์ธ์ ์ฐพ์๋ณด๋ ์ค JavaScript API๋ก๋ ๊ฐ๋ฅํ๋ค๊ณ ํด์ ์ ๋ฆฌํด๋ณด๊ณ ์ํ๋ค.
์ฌ์ฉํด์ผ๋๋ ์ด์
scroll event
๋ก๋ ๊ตฌํ์ด ๊ฐ๋ฅํ์ง๋ง ์ฌ์ฉ์๊ฐ ์คํฌ๋กค์ ๋ฐ์์ํฌ๋ ๋ง๋ค ํธ์ถ๋๊ธฐ ๋๋ฌธ์ ๋ฉ์ธ ์ค๋ ๋(Main Thread)์ ์ํฅ์ ์ค๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋๋ฐ์ด์ฑ(Debouncing)๊ณผ ์ฐ๋กคํ๋ง(Throttling)์ ์ฌ์ฉํด์ผ ํ๋ค.
๋ํ getBoundingClientRect()
ํจ๊ผ ์ฌ์ฉํด์ผํ๋๋ฐ ์ด ํจ์๋ ๋ฆฌํ๋ก์ฐ๊ฐ ๋ฐ์ํ๋ค.
์ฐ๋กคํ๋ง / Throttling : ๋ง์ง๋ง ํจ์๊ฐ ํธ์ถ๋ ํ ์ผ์ ์๊ฐ์ด ์ง๋๊ธฐ ์ ์ ๋ค์ ํธ์ถ๋์ง ์๋๋ก ํ๋ ๊ฒ
๋ฆฌํ๋ก์ฐ / reflow :๋ธ๋ผ์ฐ์ ๊ฐ ์์๋ ๋ํ์ ๋ค์ ๊ณ์ฐํ์ฌ ๊ทธ๋ฆฌ๋ ํ์
์ฌ์ฉ๋ฐฉ๋ฒ
Intersection Observer ์์ฑํ๊ธฐ
๋จผ์ IntersectionObeserver
๊ฐ์ฒด๋ฅผ ๋ง๋ ๋ค.
const observer = new intersectionObserver(callback,options)
์์ฑ์, ์ฝ๋ฐฑ ํจ์์ ์ต์ ์ ํจ๊ป ์ ๋ฌํ ์ ์๋๋ฐ, ๋จผ์ ์ต์ ๋ถํฐ ์์๋ณด์.
Options
์๋ ๊ทธ๋ฆผ์ ์ฐธ๊ณ ํ๋ฉด ์ดํดํ๊ธฐ ์ฝ๋ค.
root
: ์ด ์์๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ด์ฐฐํ๊ณ ์ํ๋ ์์์ ๊ฐ์์ฑ์ ๊ฒฐ์ ํ๋ค. (default
: ๋ธ๋ผ์ฐ์ viewport)rootMargin
: ๋จ์ด์ ๋ป ๊ทธ๋๋ก root๊ฐ ๊ฐ๋ margin ๊ฐ์ด๋ค. (default
: 0)threshold
: root๋ฅผ ๊ธฐ์ค์ผ๋ก ๋์์์๊ฐ ์ผ๋ง๋งํผ ๋ณด์ผ๋ ์ฝ๋ฐฑํจ์๋ฅผ ์คํํ ์ง 0~1 ์ฌ์ด์ ๊ฐ์ผ๋ก ๋ํ๋ธ๋ค. ๋ง์ฝ ์์๊ฐ 25%์ฉ ๋ณด์ผ๋๋ง๋ค ์คํํ๊ณ ์ถ๋ค๋ฉด[0, 0.25, 0.5, 0.75, 1]
์ ๊ฐ์ด ๋ฐฐ์ด๋ก ์์ฑํ๋ฉด ๋๋ค. (default
: 1)
Callback
์ฝ๋ฐฑํจ์๋ ๋๊ฐ์ง์ ์ธ์๋ฅผ ๋ฐ์ ์ ์๋๋ฐ, entries์ obeserver ์ด๋ค.
const observer = new intersectionObserver((entries,observer)=>{
entries.forEach((entry) => {
console.group('Intersection Observer Entry');
console.log(entry.boundingClientRect);
console.log(entry.intersectionRatio);
console.log(entry.intersectionRect);
console.log(entry.isIntersecting);
console.log(entry.rootBounds);
console.log(entry.target );
console.log(entry.time);
console.groupEnd()
})
})
entries
: Intersection Observer Entry ์ ๋ฐฐ์ด๊ฐ์ด๋ค. ์ฝ๊ฒ ๋งํด์ ๋ฑ๋ก๋ ๋์์์๋ค์ ๋ฐฐ์ด๊ฐ ์ด๋ค.
Intersection Observer Entry ์ด ๊ฐ์ฒด๋ ์๋ ์ฝ๊ธฐ ์ ์ฉ ์์ฑ๋ค์ ๊ฐ์ง๊ณ ์๋ค.
boundingClientRect
: target์ getBoundingClientRect() ๊ฐ
intersectionRatio
: target์ด ์ผ๋ง๋งํผ ๋ ธ์ถ๋ฌ๋์ง 0~1 ์ฌ์ด์ ๊ฐ์ผ๋ก ๋ํ๋ธ๋ค. (๋ ธ์ถ๋น์จ)
intersectionRect
: ๋ ธ์ถ๋ ์์ญ์ ๋ํ ์ฌ๊ฐํ ์์ฑ๊ฐ
isIntersecting
: ๋ ธ์ถ์ฌ๋ถ๋ฅผ true/false ๊ฐ์ผ๋ก ๋ํ๋ธ๋ค.
rootBounds
: ๋ฃจํธ์ ์ฌ๊ฐํ ์์ฑ๊ฐ
target
: ๋์์์
time
: ๋์์ด ๊ต์ฐจ๋ ์๊ฐ
observer
: ๋ง๋ค์ด์ง Intersection Observer ๊ฐ์ฒด์ด๋ค.
๋ฉ์๋ ์ดํด๋ณด๊ธฐ
Intersection Observer ๊ฐ์ฒด๋ 4๊ฐ์ง์ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
๐ญ observe
: ์์์ ๋ํ ๊ด์ฐฐ์ ์์โ disconnect
: ๋ชจ๋ ๋์์์๋ค์ ๋ํ ๊ด์ฐฐ์ ์ค๋จ (์ฐ๊ฒฐ์ ๋๋๋ค.)๐ takeRecordes
: ๋ชจ๋ ๋์์์๋ค์ ๋ํ Intersection Observer Entry ๋ฐฐ์ด์ ๋ฐํโ๐ป unobserve
: ํน์ ์์์ ๋ํ ๊ด์ฐฐ์ ์ค๋จ
๋ฌดํ ์คํฌ๋กค ๋ง๋ค์ด๋ณด๊ธฐ
์. ์ด์ ๋ฌดํ ์คํฌ๋กค์ ๊ตฌํํด๋ณด์.
๊ตฌํ ๋ฐฉ๋ฒ์ ๊ฐ๋จํ๋ค.
๋จผ์ , html๋ก scroll์ด ์๊ธธ๋งํ ํฌ๊ธฐ์ ์์๋ฅผ ๋ง๋ ๋ค.
๋์ ์์๋ฅผ intersection Observer ๊ฐ์ฒด์ observe
ํ๋ค.
๊ทธ ํ ์ฝ๋ฐฑํจ์๋ก ๊ฐ์์ ๋ฐ์ดํฐ๋ฅผ ๋๋ฉฐ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ๋ง์ง๋ง์ผ๋ก ๋ง๋ค์ด์ง๋ ์์๋ฅผ ๋ค์ observe
ํ๋ ํจ์๋ฅผ ๋ฆฌํด์ํจ๋ค.
API ํ์ ํ๋ ์ ๋๋ก๋ง ์์ฃผ ๊ฐ๋จํ๊ฒ ๋ง๋ค๊บผ๋ผ CSS๋ถํฐ ๊ฐ๋จํ๊ฒ ์งฐ๋ค.
CSS ์ฝ๋ฉ
body {
width: 100%;
height: 100%;
}
/* ๋ฃ์ง ์๊ณ div์ ํฌ๊ธฐ๋ฅผ ๋๋ ค๋ ๋๋ค. */
header {
width: 500px;
height: auto;
padding: 10px;
background-color: #f9f8ed;
color: #6a9c78;
text-align: center;
margin: 10px auto 20px auto;
border-radius: 20px;
}
div {
width: 400px;
height: 400px;
border: 10px solid #c4e3cb;
border-radius: 200px;
margin: auto;
text-align: center;
line-height: 400px;
font-size: 2em;
color:forestgreen;
}
HTML ์ฝ๋ฉ
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>๋ฌดํ์คํฌ๋กค ๊ตฌํํ๊ธฐ</title>
</head>
<body>
<div></div>
<div></div>
<div id="target">target</div>
</body>
</html>
JavaScript
- Ajax๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ฉด ์ ๋ง ์ข๊ฒ ์ง๋ง, ๊ท์ฐฎ์ผ๋ ๊ฐ๋จํ๊ฒ ๋ฐ์ดํฐ๋ฅผ ๋ง๋ ๋ค.
// ๋ฐ์ดํฐ๋ฅผ ๋ง๋ ๋ค.
let data = [];
const count = 10
for(let i = 0;i < 10;i++){
data.push('์๋ก์๊ธด Element' + (i+1));
}
- ๊ด์ฐฐํ ๋์(target)๊ณผ body ํ๊ทธ๋ฅผ ๋ถ๋ฌ์จ๋ค.
const target = document.querySelector('#target');
const body = document.querySelector('body');
- ๋ฐ์ดํฐ์์์ ๋ฐ๋ณตํ๋ฉฐ
div
์์๋ฅผ ๋ง๋๋ ํจ์๋ฅผ ๋ง๋ ๋ค. ์ด ๋ ๋ง์ง๋งdiv
๋ฅผ ๊ด์ฐฐ๋์์ผ๋ก ๋ฑ๋กํ๋ค.
const createElement = (data,observer) => {
data.forEach((item,index)=>{
let div = document.createElement('div');
// ๋ฐ์ดํฐ์ ๋ง์ง๋ง ์์๋ฅผ ๊ด์ฐฐ๋์์ผ๋ก ๋ฑ๋กํ๋ค.
if(index === data.length -1){
div.innerText = "target";
observer.observe(div);
} else {
div.innerText = item;
}
body.appendChild(div);
})
}
- Insersection Obeserver ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ๋์์์๋ฅผ
observe
ํ๋ค.
const option = {
rootMargin: '0px',
threshold: 1.0
}
const observer = new IntersectionObserver((entries,observer)=>{
console.log(entries);
entries.forEach((entry,index)=>{
console.log(entries[index]);
if(entry.isIntersecting){
return createElement(data,observer);
} else {
return;
}
})
},option);
observer.observe(target);
์์ฑ!
์ฐธ๊ณ ํ ๋ฌธ์
http://blog.hyeyoonjung.com/2019/01/09/intersectionobserver-tutorial
https://velog.io/@meganatc7/Intersection-Observer-%EB%9E%80
https://developer.mozilla.org/ko/docs/Web/API/Intersection_Observer_API
https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry
https://developer.mozilla.org/ko/docs/Web/API/IntersectionObserver/IntersectionObserver
Author And Source
์ด ๋ฌธ์ ์ ๊ดํ์ฌ([JS ] ๐ญ Intersection Observer API ์์๋ณด๊ธฐ), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://velog.io/@909backdev/JavaScript-Intersection-Observer-API-์์๋ณด๊ธฐ์ ์ ๊ท์: ์์์ ์ ๋ณด๊ฐ ์์์ URL์ ํฌํจ๋์ด ์์ผ๋ฉฐ ์ ์๊ถ์ ์์์ ์์ ์ ๋๋ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค