[JavaScript] IntersectionObserver

๋ฉ”ํƒ€๋ชฝยท2023๋…„ 9์›” 3์ผ
post-thumbnail

๐Ÿ’ก IntersectionObserver

๋ทฐํฌํŠธ ์‚ฌ์ด์˜ ๊ต์ฐจ ์˜์—ญ์„ ๊ฐ์‹œํ•˜๊ณ , ํ•ด๋‹น ๊ต์ฐจ ์˜์—ญ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” API๋‹ค.
์ด๋ฅผ ํ†ตํ•ด ์Šคํฌ๋กค, ๋ฌดํ•œ์Šคํฌ๋กค, ์ด๋ฏธ์ง€ ๋กœ๋”ฉ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.



IntersectionObserver์˜ ์ฃผ์š” ํŠน์ง•

1. ๋น„๋™๊ธฐ์  ๊ฐ์‹œ
IntersectionObserver๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์š”์†Œ์˜ ๊ต์ฐจ ์ƒํƒœ๋ฅผ ๊ฐ์‹œํ•œ๋‹ค.
2. ๋น„๋™๊ธฐ์  ์ฝœ๋ฐฑ ์‹คํ–‰
๊ต์ฐจ ์˜์—ญ์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
์ด๋ฅผ ํ†ตํ•ด ๊ต์ฐจ ์˜์—ญ์˜ ๋ณ€ํ™”์— ๋”ฐ๋ผ ๋™์ž‘์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
3. ๋ฃจํŠธ ์š”์†Œ์™€ ํƒ€๊ฒŸ ์š”์†Œ
๊ต์ฐจ ์˜์—ญ์„ ๊ด€์ฐฐํ•˜๋Š” ์š”์†Œ ๋ฃจํŠธ(root)
๊ต์ฐจ ์˜์—ญ์„ ๊ฐ์‹œํ•˜๋Š” ๋Œ€์ƒ ์š”์†Œ ํƒ€๊ฒŸ(target)
๋ฃจํŠธ ์š”์†Œ๋Š” ๋Œ€์ƒ ์š”์†Œ์™€ ๊ต์ฐจํ•˜๋Š” ์˜์—ญ์„ ๊ด€์ฐฐํ•˜๊ณ , ๋ฃจํŠธ ์š”์†Œ์˜ ๊ธฐ๋ณธ ๊ฐ’์€ ๋ทฐํฌํŠธ๋‹ค.
4. ๊ต์ฐจ ์ƒํƒœ ์ •๋ณด
์ฝœ๋ฐฑ ํ•จ์ˆ˜์— ์ „๋‹ฌ๋˜๋Š” ์ธ์ž์—๋Š” ๊ต์ฐจ ์ƒํƒœ ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ๋‹ค.
์ด ์ •๋ณด๋Š” ๋Œ€์ƒ ์š”์†Œ์™€ ๋ฃจํŠธ ์š”์†Œ ๊ฐ„์˜ ๊ต์ฐจ ์˜์—ญ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•œ๋‹ค.


IntersectionObserver ์‚ฌ์šฉ ๋ฒ”์œ„

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


IntersectionObserver ์‚ฌ์šฉ ์˜ˆ์‹œ

์Šคํฌ๋กค์ด ๋์„ ๋•Œ, ๋งˆ์ง€๋ง‰ ์•„์ดํ…œ์ด ๊ฐ์ง€๋˜๋ฉด ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋“ค์ด ๋ฟŒ๋ ค์ง€๋Š” ๋ฌดํ•œ์Šคํฌ๋กค ์ฝ”๋“œ๋กœ ์˜ˆ์‹œ๋ฅผ ๋“ค์–ด๋ณด์ž.

listObserver = new IntersectionObserver((items, observer) => {
  items.forEach((item) => {
	// ์•„์ดํ…œ์ด ํ™”๋ฉด์— ๋ณด์ผ ๋•Œ
  	if (item.isIntersecting){
    	// ์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•œ๋‹ค
      	item.target.querySelector('img').src = item.target.querySelector('img').dataset.src;
                                                                         
	  	// ๋งˆ์ง€๋ง‰ ์š”์†Œ์•ˆ์ž ํ™•์ธ
        let dataIndex = Number(item.target.dataset.index);
      	// ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ผ๋ฉด
      	if (dataIndex + 1 === this.data.length){
          	// nextPage๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค
        	this.onNextPage();
        }
    }
  });
});

item.isIntersecting์€ ํ•ด๋‹น ์•„์ดํ…œ์ด ํ˜„์žฌ ๋ทฐํฌํŠธ์— ๋ณด์ด๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ถˆ๋ฆฌ์–ธ ๊ฐ’์ด๋‹ค.

item.target.querySelector('img').src = item.target.querySelector('img').dataset.src;

์•„์ดํ…œ์ด ํ™”๋ฉด์— ๋ณด์ด๋ฉด ์ด๋ฏธ์ง€์˜ 'src'์†์„ฑ์„ ํ•ด๋‹น ์ด๋ฏธ์ง€ ์š”์†Œ์˜ data-src์†์„ฑ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•ด ์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•œ๋‹ค.
์†์„ฑ๊ฐ’์„ ์‚ฌ์šฉํ•ด ์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•˜๋Š” ์ด์œ ๋Š” ์ง€์—ฐ๋กœ๋”ฉ(lazy loading)์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋‹ค.
์ง€์—ฐ ๋กœ๋”ฉ์€ ์›น ํŽ˜์ด์ง€์˜ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋กœ, ์ดˆ๊ธฐ ๋กœ๋”ฉ ์‹œ์—๋Š” ์ด๋ฏธ์ง€๋ฅผ ์‹ค์ œ๋กœ ๋กœ๋“œํ•˜์ง€ ์•Š๊ณ  ํ•„์š”ํ•  ๋•Œ๋งŒ ๋กœ๋“œํ•˜๋Š” ๋ฐฉ์‹์„ ์˜๋ฏธํ•œ๋‹ค.
์ด๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

let dataIndex = Number(item.target.dataset.index);
ํ•ด๋‹น ์•„์ดํ…œ์˜ ์ธ๋ฑ์Šค๋ฅผ ๊ฐ€์ ธ์™€์ค€๋‹ค.

dataIndex + 1 === this.data.length
ํ•ด๋‹น ์•„์ดํ…œ์ด ๋ฐ์ดํ„ฐ์˜ ๋งˆ์ง€๋ง‰ ์•„์ดํ…œ์ธ์ง€์˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ด์ค€๋‹ค.
dataIndex์— 1์„ ๋”ํ•ด์ค€ ์ด์œ ๋Š” ๋ฐฐ์—ด์˜ ์ธ๋ฑ์Šค๊ฐ€ 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋งˆ์ง€๋ง‰ ์•„์ดํ…œ์„ ํ™•์ธํ•ด ์ฃผ๊ธฐ ์œ„ํ•ด +1์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

render() {
	~~~~๋ Œ๋”๋˜๋Š” ๋…€์„๋“ค
    this.$result.querySelectorAll('.item').forEach(($item, index) => {
    	this.listObserver.observe($item);
    });
}

์ด์ œ render๋˜๋Š” ์˜์—ญ์—์„œ ํ™”๋ฉด์— ๋ฟŒ๋ ค์ง„ ์•„์ดํ…œ๋“ค์— observe๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.
์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋งˆ์ง€๋ง‰ ์•„์ดํ…œ์ด ํ™”๋ฉด์— ๋ณด์ผ ๋•Œ ์ƒˆ๋กœ์šด ์ด๋ฏธ์ง€๊ฐ€ ๋กœ๋”ฉ๋˜๋ฉฐ ๋ฌดํ•œ ์Šคํฌ๋กค์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

profile
๋‚ด๊ฐ€๋ณด๋ ค๊ณ ๋งŒ๋“ ๋ฒจ๋กœ๊ทธ

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