๐Ÿ” Intersection Observer API

Kyeongeun Joยท2022๋…„ 6์›” 1์ผ
0
post-thumbnail

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ ์ค‘ ๊ฐ€์žฅ ์• ๋ฅผ ๋จน์—ˆ๋˜ ์˜ค๋””์˜ค ๋ฐ ๋น„๋””์˜ค์˜ ์ค‘์ฒฉ์„ ๋ง‰๊ณ ์žํ•˜๋Š” ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ ํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

์˜ค๋””์˜ค, ๋น„๋””์˜ค, ์ด๋ฏธ์ง€ ์—ฌ๋Ÿฌ๊ฐœ ๋“ฑ ๋‹ค์–‘ํ•œ ์ฝ˜ํ…์ธ ๋“ค์ด ๋‚˜์—ด๋˜์–ด ์žˆ๋Š” ์ƒํƒœ์—์„œ ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์—†๊ฒŒ๋” ์ž‘์—…์„ ํ•ด์•ผํ–ˆ๋‹ค. ์–ด๋ ค์šธ๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐํ•ด ๊ธฐํš์ž๋‹˜๊ณผ ํ•จ๊ป˜ ์ด์•ผ๊ธฐ ํ•˜๋ฉฐ ์›ํ™œํ•œ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ณด๊ณ ์ž ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ์•ˆ๋“ค์„ ๋งŒ๋“ค์–ด๋ณด์•˜๋Š”๋ฐ

1. ํ”Œ๋ ˆ์ด๋ฅผ ์ปจํŠธ๋กคํ•˜๋Š” ๋ณด์ด์ง€ ์•Š๋Š” player๋ฅผ ๋งŒ๋“ค์–ด์„œ, ๊ทธ ๊ฐ์ฒด ํ•˜๋‚˜๋กœ์„œ๋งŒ ์ž‘๋™ ์‹œํ‚จ๋‹ค.
	-> ์˜ค๋””์˜ค๋Š” ์žฌ์ƒ์ด ๋˜์ง€๋งŒ ๋น„๋””์˜ค์˜ ์˜์ƒ์ด ๋ณด์ด์ง€ ์•Š๋Š” ์ด์Šˆ
2. ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ”Œ๋ ˆ์ด๋“ค์˜ ์žฌ์ƒ์„ ๊ฐ์ง€ํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ current Player์ด์™ธ์˜ ๊ฒƒ๋“ค์€ ๋ชจ๋‘ pause ์‹œํ‚ด
	-> ์‹ค์ œ๋กœ 1000๊ฑด์ด ๋„˜๋Š” ์ฝ˜ํ…์ธ ๋“ค๋กœ ๋„˜์ณ๋‚˜๋‹ค๋ฉด? (๐Ÿค”) ํ•˜๋Š” ๊ถ๊ธˆ์ฆ๊ณผ ์œ„ํ—˜์„ฑ ๋ฐœํ–‰ 

๋•Œ๋ฌธ์— ๋˜ ๋‹ค๋ฅธ ์‰ฌ์šด ๋ฐฉ๋ฒ•์ด ์žˆ๊ฒ ์ง€๋งŒ ๊ธฐํš์ž๋‹˜์˜ ์›ํ™œํ•œ ์†Œํ†ต๊ณผ ํ†ต์พŒํ•œ ์Šน๋ฝ์œผ๋กœ ๊ฒฐ๊ณผ์ ์œผ๋กœ๋Š” ํ™”๋ฉด์˜ ๋ทฐํฌํŠธ์— ๋„๋‹ฌํ–ˆ์„ ๋•Œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ๋‚˜์„ ๋“ฏ ํ–ˆ๋‹ค.

Intersection Observer API ๋ž€ ๋ฌด์—‡์ธ๊ฐ€.

ํŠน์ • ์š”์†Œ(target)๊ฐ€ ๊ทธ ์š”์†Œ์˜ ๋ถ€๋ชจ๋‚˜ ๋ทฐํฌํŠธ์— ๊ต์ฐจํ•˜๋Š”์ง€๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๊ฐ์ง€ํ•˜์—ฌ, ๊ต์ฐจํ•  ๋•Œ๋งˆ๋‹ค ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” API์ด๋‹ค.

Intersection Observer๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด

const observer = new Intersection Observer(**callbackFunction**, **options**) {
	observer.observe(targetElement)
}
  1. ์š”์†Œ๋“ค์ด ๊ต์ฐจ๋˜์—ˆ์„ ๋•Œ ์‹คํ–‰ํ•  ์ฝœ๋ฐฑํ•จ์ˆ˜
  2. options
  • root : ํƒ€๊ฒŸ์ด ๋ณด์ด๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ์œ„ํ•œ ๋ทฐํฌํŠธ์ด๋ฉฐ, ๋”ฐ๋กœ ํŠน์ •์ง€์–ด์ฃผ์ง€ ์•Š์œผ๋ฉด ๋ธŒ๋ผ์šฐ์ € ๋ทฐํฌํŠธ๋ฅผ ๋œปํ•œ๋‹ค.
  • rootMargin : ๋ฃจํŠธ์š”์†Œ๋ฅผ ๋‘˜๋Ÿฌ์‹ผ ๋ฐ•์Šค์— ๋Œ€ํ•œ ๊ฐ’์œผ๋กœ ๋ง๊ทธ๋Œ€๋กœ margin๊ฐ’์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
  • threshold : ์›ํ•˜๋Š” ์š”์†Œ๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋…ธ์ถœ๋˜์—ˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” intersection ratio์ด๋ฉฐ, 0-1์˜ ๊ฐ’์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
    (๊ฐ’์ด 0 => ์š”์†Œ๊ฐ€ 1px์ด๋ผ๋„ ๋ณด์ด๋ฉด ์ฝœ๋ฐฑํ•จ์ˆ˜ ์‹คํ–‰, ๊ฐ’์ด 1 => ์š”์†Œ๊ฐ€ ๋ชจ๋‘ ๋ณด์—ฌ์•ผ ์‹คํ–‰)

์‚ฌ์šฉํ•œ ๋ฐฉ๋ฒ•

  • ๊ด€์ฐฐ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ผ๋Š” ํƒ€๊ฒŸ ์š”์†Œ๋ฅผ ์ •ํ•œ๋‹ค.
    video, audio๋ฅผ ๊ฐ์‹ธ๊ณ ์žˆ๋Š” ๊ฐ์ฒด๋“ค๋กœ ์„ค์ •
    (audio์˜ ๊ฒฝ์šฐ์—๋Š” ๋‹ค๋ฅธ ์š”์†Œ๋“ค์ด ์ถ”๊ฐ€์ ์œผ๋กœ ํ•„์š”ํ–ˆ๊ธฐ์—, ๋น„๋””์˜ค์™€ ๋‹ค๋ฅธ ๋กœ์ง์œผ๋กœ ๊ตฌํ˜„์ด ๋˜์–ด์žˆ๋‹ค.)
  • ๋Œ€์ƒ ์š”์†Œ๊ฐ€ ํ™”๋ฉด์— ๋ณด์ด๋Š” ์ •๋„์— ๋”ฐ๋ผ ์‹คํ–‰๋˜๋Š” ์ด๋ฒคํŠธ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค.
    ๋ทฐํฌํŠธ์— ๋…ธ์ถœ์ด ๋˜๋ฉด video๋Š” mute, autoplay๊ฐ€ ๋˜๋ฉฐ, ์˜ค๋””์˜ค๋Š” ํด๋ฆญํ•˜์—ฌ ์žฌ์ƒํ•˜๋˜,
    ๋ทฐํฌํŠธ ์˜์—ญ ๋ฐ–์œผ๋กœ ๋ฒ—์–ด๋‚˜๋ฉด ์ž๋™์œผ๋กœ pause ๋œ๋‹ค.
  • ๋งŒ๋“ค์–ด ๋†“์€ ์ฝœ๋ฐฑํ•จ์ˆ˜๋Š” IntersectionObserverEntry์˜ entry ๊ฐ์ฒด ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ›๊ฒŒ๋œ๋‹ค.
    useEffect(() => {
    	// ์˜ต์…˜ ์„ค์ •
        const options = {
            root: null,
            rootMargin: '-200px', // ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด๋ณด๋‹ค ์ž‘๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•จ
            threshold: 0.5,
        }
        
        const intersectionObserver = new IntersectionObserver((entries, observer) => {
        
			// ๊ด€์ฐฐํ•  ๊ฐ์ฒด๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์ด๋ฏ€๋กœ forEach ์‚ฌ์šฉ
            entries.forEach(entry => {
                let type = entry.target.nodeName;
                
                // ๋ทฐํฌํŠธ์—์žˆ๋Š” target ์š”์†Œ๊ฐ€ true์ผ ๋•Œ
                if (entry.isIntersecting) {
                    if (entry.intersectionRatio > 0) {
                        if (type === 'VIDEO') {
                        
                       		// ์ ์šฉ๋˜๋Š” video ์ž๋™์žฌ์ƒ event
                            entry.target.play();
                            entry.target.nextElementSibling.classList.remove(styles.videoPlayIcon);
                            entry.target.addEventListener('timeupdate', (e) => {
                                let progress = entry.target.nextElementSibling.nextElementSibling;
                                progress.max = Math.floor(entry.target.duration);
                                progress.value = Math.floor(entry.target.currentTime);
                            })
                        }
                    }
                } else {
                	// ๋ทฐํฌํŠธ์˜ ์˜์—ญ์—์„œ ๋ฒ—์–ด๋‚ฌ์„ ๋•Œ
                    if (type === 'VIDEO') {
                        entry.target.pause();
                        entry.target.nextElementSibling.classList.add(styles.videoPlayIcon);
                    } else if (type === 'DIV') {
                    	// audio์˜ ๊ฒฝ์šฐ์—๋Š” clickํ•ด์•ผ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ์ด๊ธฐ์—, pause ๊ธฐ๋Šฅ๋งŒ ์ถ”๊ฐ€ํ–ˆ๋‹ค.
                        let audio = entry.target.children[1];
                        audio.nextElementSibling.classList.remove(styles.active);
                        audio.nextElementSibling.nextElementSibling.classList.remove(styles.pause);
                        return audio.pause();
                    }
                }
            })
        }, options);
        
        // observing ๋  ๊ฐ์ฒด๋“ค
        const content = document.querySelectorAll('.observerItem');
        content.forEach(target => {
            intersectionObserver.observe(target);
        })
    }, [])

entries

observer

๋ฆฌ์•กํŠธ ์ž์ฒด ๋‚ด์—์„œ ์ง์ ‘์ ์ธ DOM(๊ฐ์ฒด)์กฐ์ž‘์„ ํ”ผํ•˜๊ธฐ๋ฅผ ๊ถŒ์žฅํ•˜๋ฉฐ,
( ๐Ÿ’๐Ÿปโ€โ™€๏ธ ? ์ƒํƒœ๊ด€๋ฆฌ์— ๊ด€ํ•˜์—ฌ ์ง์ ‘์ ์ธ DOM ๋‚ด๋ถ€์™€ React ๋‚ด๋ถ€์˜ ์ƒํƒœ๋ฅผ ํ˜ผํ•ฉํ•˜๋ฉด ์ถ”๋ก ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๊ณ , ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ์–ด๋ ค์›Œ์ง€๋ฏ€๋กœ)
๋ฆฌ์•กํŠธ์™€ ๊ด€๋ จ๋œ DOM Selector ์ฐธ๊ณ 

๋˜ํ•œ ๋ฆฌ์•กํŠธ์—์„œ๋Š” ํŠน์ • DOM์— ์ ‘๊ทผํ•  ๋•Œ์—๋Š” useRef() ๋ผ๋Š” ํ›…์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—
querySelector ์— ์ต์ˆ™ํ•ด์žˆ๋˜ ๋‚˜๋Š”
๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์„ ์ฐพ๋Š”๋ฐ์— ๋”์šฑ ์–ด๋ ค์›€์„ ๋Š๋‚€๊ฒŒ ์•„๋‹Œ๊ฐ€ ์‹ถ๋‹ค.

๋ถ€๊ฐ€์ ์œผ๋กœ Intersection Observer๋Š” ๋ณดํ†ต ๋ฌดํ•œ์Šคํฌ๋กค๋ง ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๋•Œ ์ž์ฃผ ์“ฐ์ด๊ธฐ ๋•Œ๋ฌธ์—,
๋ฌดํ•œ์Šคํฌ๋กค๋ง ๊ธฐ๋Šฅ์ฒ˜๋Ÿผ ํ•˜๋‹จ์— ๋ทฐํฌํŠธ๋ฅผ ๋‹ฌ์•„๋†“๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ๋ธŒ๋ผ์šฐ์ €์˜ ์ž์ฒด์˜ ๋ทฐํฌํŠธ๋ฅผ ๊ณ ๋ คํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋งŽ์ง€ ์•Š์•˜๋‹ค.

์ด ๊ฒƒ ์ด์™ธ์—๋„ ๋‹ค์–‘ํ•œ ๊ณณ์— ํ™œ์šฉ๋„๊ฐ€ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค๋ผ๋Š” ์ƒ๊ฐ๊ณผ,
์“ธ ์ค„ ์•Œ์•„์•ผ ์ž˜์“ด๋‹ค๋ผ๋Š” ์ƒ๊ฐ์ด ๋‹ค์‹œํ•œ๋ฒˆ ๋“ ๋‹ค.๐Ÿ˜Š !

0๊ฐœ์˜ ๋Œ“๊ธ€