๊ฐœ๋ฐœ ๊ณต๋ถ€/๋ฐ๋ธŒ์ฝ”์Šค TIL

[ํด๋ผ์šฐ๋”ฉ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์—”์ง€๋‹ˆ์–ด๋ง TIL] 240118 - ๊ณ ์–‘์ด ์‚ฌ์ง„ ๊ฒ€์ƒ‰ ์‹ค์Šต 2

๊ฐ€์šค์ด 2024. 1. 19. 13:50

Intro


๊ฐ•์˜๊ฐ€ ๋ฐ€๋ฆฌ๋‹ˆ๊นŒ ๋ถ€๋‹ด์ด ํฌ๋‹ค...

๊ณผ์ œ๋ฅผ ๋จผ์ € ํ’€์–ด๋ณผ๊นŒ ํ–ˆ๋Š”๋ฐ ์ƒ๊ฐ๋ณด๋‹ค ๋ณต์žกํ•ด์„œ ํ•ด์„ค ๊ฐ•์˜๋ฅผ ๋“ฃ๊ณ  ๋ณต์Šต์ฐจ ๊ณผ์ œ๋ฅผ ํ’€์–ด๋ณด๋ ค ํ•œ๋‹ค.

์˜ค๋Š˜์€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋กœ ๋ชจ๋‹ฌ ์ œ์–ดํ•˜๋Š” ๊ฒƒ๊ณผ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€ ์ €์žฅํ•˜๊ณ  ๋ถˆ๋Ÿฌ์˜ค๊ธฐ, ๋‹ค์Œ ํŽ˜์ด์ง€ api ์š”์ฒญํ•˜๊ธฐ๋ฅผ ์‹ค์Šตํ–ˆ๋‹ค.

 

 

 

์˜ค๋Š˜ ํ•™์Šตํ•œ ๋‚ด์šฉ

: ๋ชจ๋‹ฌ์ œ์–ด, ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€, ์Šคํฌ๋กค๋‹ค์ŒํŽ˜์ด์ง€


 

๐Ÿ‘ฉ‍๐Ÿ’ป ๋ชจ๋‹ฌ ์ฐฝ ์ œ์–ด
์ด๋ฏธ์ง€๋ฅผ ๊ฒ€์ƒ‰ํ•œ ํ›„ ๊ฒฐ๊ณผ๋กœ ์ฃผ์–ด์ง„ ์ด๋ฏธ์ง€๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋ชจ๋‹ฌ์ด ๋œจ๋Š”๋ฐ, ๋ชจ๋‹ฌ ์˜์—ญ ๋ฐ–์„ ๋ˆ„๋ฅด๊ฑฐ๋‚˜ / ํ‚ค๋ณด๋“œ์˜ ESC ํ‚ค๋ฅผ ๋ˆ„๋ฅด๊ฑฐ๋‚˜ / ๋ชจ๋‹ฌ ์šฐ์ธก์˜ ๋‹ซ๊ธฐ(x) ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋‹ซํžˆ๋„๋ก ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

๋‹ซ๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ || ๋ชจ๋‹ฌ ์˜์—ญ ๋ฐ– ํด๋ฆญ ์‹œ ๋ชจ๋‹ฌ ์ฐฝ ๋‹ซ๊ธฐ

this.$imageInfo.addEventListener('click', (e) => {
  if (e.target.className === 'ImageInfo' || e.target.className === 'close') this.closeImageInfo();
});

 

event.target์œผ๋กœ ์–ด๋–ค ์š”์†Œ๋ฅผ ํด๋ฆญํ–ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

๋ชจ๋‹ฌ ์ฐฝ ๋ฐ”๊นฅ ์˜์—ญ์€ className์ด ImageInfo์ธ div ์š”์†Œ์ด๋ฏ€๋กœ className์ด ImageInfo์ธ ์š”์†Œ๋ฅผ ํด๋ฆญํ–ˆ์„ ๊ฒฝ์šฐ์™€ ๋˜๋Š” close๋ผ๋Š” ํด๋ž˜์Šค ๋„ค์ž„์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฒ„ํŠผ ์š”์†Œ๋ฅผ ํด๋ฆญํ–ˆ์„ ๊ฒฝ์šฐ์— ์ฐฝ์„ ๋‹ซ๋Š” ์ด๋ฒคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

 

 

ํ‚ค๋ณด๋“œ์˜ ESC ํ‚ค๋ฅผ ๋ˆŒ๋Ÿฌ ๋ชจ๋‹ฌ์ฐฝ ๋‹ซ๊ธฐ

: Escape ํ‚ค๊ฐ€ ๋ˆŒ๋ ธ๋‹ค๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๊ฐ์ง€๋˜์—ˆ์„ ๋•Œ, ๋™์ž‘์„ ์‹คํ–‰ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

KeyboardEvent๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. KeyboardEvent์˜ ์œ ํ˜•์œผ๋กœ๋Š” keypress, keyup, keydown์ด ์žˆ๋‹ค.

 

keypress, keyup, keydown ์ฐจ์ด

โš ๏ธ keypress๋Š” ๋” ์ด์ƒ ๊ถŒ์žฅ๋˜์ง€ ์•Š๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ์‚ฌ์šฉํ•˜์ง€ ๋ง ๊ฒƒ

 

keypress๋Š” ๋ฌธ์ž ๊ฐ’์„ ์ƒ์„ฑํ•˜๋Š” ํ‚ค๋ฅผ ๋ˆ„๋ฅด๋ฉด ์ด๋ฒคํŠธ๊ฐ€ ์‹œ์ž‘๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ํ•œ๊ธ€ ์ž…๋ ฅ ์‹œ์—๋Š” ์ •์ƒ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Escape ์ž…๋ ฅ๋„ ๋ฐ›์„ ์ˆ˜ ์—†๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

keydown์€ ํ‚ค๋ฅผ ๋ˆ„๋ฅผ ๋•Œ ์ด๋ฒคํŠธ๊ฐ€ ์‹œ์ž‘๋œ๋‹ค. keypress์™€ ๋™์ž‘ํ•˜๋Š” ๊ฒŒ ๊ฐ™์ง€๋งŒ ๋ฌธ์ž ๊ฐ’ ์ƒ์„ฑ ์—ฌ๋ถ€์— ๊ด€๊ณ„ ์—†์ด ๋ชจ๋“  ํ‚ค์— ๋Œ€ํ•ด ์ด๋ฒคํŠธ๊ฐ€ ์‹œ์ž‘๋˜๋Š” ์ฐจ์ด์ ์ด ์žˆ๋‹ค.

๋ฐ˜๋Œ€๋กœ, keyup์€ ํ‚ค๋ฅผ ๋†“์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ์ด๋‹ค.

 

๋‹ค์Œ์€ esc ํ‚ค๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ, ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ ์ž ํ•  ๋•Œ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ ์˜ˆ์‹œ์ด๋‹ค.

document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') this.closeImageInfo();
});

 

e.key๋ฅผ ํ†ตํ•ด ์–ด๋–ค ํ‚ค๊ฐ€ ๋ˆŒ๋ ธ๋Š” ์ง€ ํŒŒ์•…ํ•˜๊ณ  ์กฐ๊ฑด๋ฌธ์„ ์‚ฌ์šฉํ•ด ์ปจํŠธ๋กคํ•  ์ˆ˜ ์žˆ๋‹ค.

 

keyboardEvent ์ธ์Šคํ„ด์Šค ์†์„ฑ

  • KeyboardEvent.code

์ด๋ฒคํŠธ๊ฐ€ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฌผ๋ฆฌ์  ํ‚ค์˜ ์ฝ”๋“œ ๊ฐ’์„ ๋ฌธ์ž์—ด๋กœ ๋ฐ˜ํ™˜

ex) KeyA, KeyB, Digit1, Digit2, Backquote, Backspace, Enter, ControlLeft...

 

  • KeyboardEvent.key

์ด๋ฒคํŠธ๊ฐ€ ๋‚˜ํƒ€๋‚ด๋Š” ํ‚ค์˜ ํ‚ค ๊ฐ’์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜

ex) a, b, 1, 2, `, Backspace, Enter, Control...

 

 

 

 


๐Ÿ‘ฉ‍๐Ÿ’ป ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€ ๋‹ค๋ฃจ๊ธฐ
์ตœ๊ทผ ๊ฒ€์ƒ‰ํ•œ ํ‚ค์›Œ๋“œ๋ฅผ SearchInput ์•„๋ž˜์— ํ‘œ์‹œ๋˜๋„๋ก ๋งŒ๋“ค๊ณ , ํ•ด๋‹น ์˜์—ญ์— ํ‘œ์‹œ๋œ ํŠน์ • ํ‚ค์›Œ๋“œ๋ฅผ ๋ˆ„๋ฅด๋ฉด ๊ทธ ํ‚ค์›Œ๋“œ๋กœ ๊ฒ€์ƒ‰์ด ์ผ์–ด๋‚˜๋„๋ก ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋‹จ, ๊ฐ€์žฅ ์ตœ๊ทผ์— ๊ฒ€์ƒ‰ํ•œ 5๊ฐœ์˜ ํ‚ค์›Œ๋“œ๋งŒ ๋…ธ์ถœ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•ด๋„ ๋งˆ์ง€๋ง‰ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํ™”๋ฉด์ด ์œ ์ง€๋˜๋„๋ก ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

 

localStorage

๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€(localStorage)๋ฅผ ํ†ตํ•ด ๋กœ์ปฌ ์ €์žฅ์†Œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋Š” ํŽ˜์ด์ง€๋‚˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋‹ซ์•„๋„ ๋‚ด์šฉ์„ ๊ธฐ์–ตํ•˜๋Š” ์ €์žฅ์†Œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

sessionStorage์™€ ๋น„์Šทํ•˜๋‚˜ ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€๋Š” ํŽ˜์ด์ง€ ์„ธ์…˜์ด ๋๋‚  ๋•Œ, ์ฆ‰ ํŽ˜์ด์ง€๋ฅผ ๋‹ซ์„ ๋•Œ ์‚ฌ๋ผ์ง€๋Š” ์ ์ด ๋‹ค๋ฅด๋‹ค.

 

๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋Š” key / value ํ˜•ํƒœ๋กœ ์ €์žฅ๋˜๋ฉฐ, value๋Š” ํ•ญ์ƒ ๋ฌธ์ž์—ด์ด๋‹ค.

๋”ฐ๋ผ์„œ ๋ฐฐ์—ด์ด๋‚˜ ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•  ๊ฒฝ์šฐ์—” JSON ํŒŒ์‹ฑํ•˜๊ฑฐ๋‚˜ split์„ ํ†ตํ•ด ๋ฌธ์ž์—ด์„ ๋ฐฐ์—ด๋กœ ๋ฐ”๊พธ๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•˜๋‹ค.

  • ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€ ๊ฐ’ ์ถ”๊ฐ€ํ•˜๊ธฐ
localStorage.setItem('lastResult', JSON.stringify(result))
  • ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€ ๊ฐ’ ์ฝ์–ด์˜ค๊ธฐ
JSON.parse(localStorage.getItem('lastResult'))
  • ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€ ๊ฐ’ ์‚ญ์ œํ•˜๊ธฐ
localStorage.removeItem('lastResult')

 

 

 

 

 


๐Ÿ‘ฉ‍๐Ÿ’ป ์Šคํฌ๋กค & ๋‹ค์Œ ํŽ˜์ด์ง€ ๋กœ๋”ฉ
๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํ™”๋ฉด์—์„œ ์œ ์ €๊ฐ€ ๋ธŒ๋ผ์šฐ์ € ์Šคํฌ๋กค ๋ฐ”๋ฅผ ๋๊นŒ์ง€ ์ด๋™์‹œ์ผฐ์„ ๊ฒฝ์šฐ, ๊ทธ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ๋กœ๋”ฉํ•˜๋„๋ก ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๊ณผ์ œ API ๋ช…์„ธ์— page์— ๋Œ€ํ•œ ๋‚ด์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์ฒ˜๋Ÿผ ์ž‘์—…์„ ํ•ด์ฃผ์„ธ์š”- /cats/search?page=1, /cats/search?page=2์ฒ˜๋Ÿผ ์—”๋“œํฌ์ธํŠธ์— page๋ผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ์„ธ์š”- 1ํŽ˜์ด์ง€๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ถ™์ผ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.- page ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ œ์–ดํ•˜๋Š” ์ƒํƒœ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ž‘์„ฑํ•ด ๋ณด์„ธ์š”.

 

getBoundingClientRect()

: ์—˜๋ฆฌ๋จผํŠธ์˜ ํฌ๊ธฐ์™€ ๋ทฐํฌํŠธ์— ์ƒ๋Œ€์ ์ธ ์œ„์น˜ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” DOMRect ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

top, bottom, left, right ๊ฐ’์„ ๋ฝ‘์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

๋ฐ์ดํ„ฐ ์–‘์ด ๋งŽ์•„์ง€๋ฉด ๊ณ„์† ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์›์ธ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

 

IntersectionObserver

์„ ํƒํ•œ ์š”์†Œ์™€ ๋ทฐํฌํŠธ๋ฅผ ๊ด€์ฐฐํ•ด ํ•ด๋‹น ์š”์†Œ๊ฐ€ ํ™”๋ฉด์— ๋ณด์ด๋Š” ์ง€ ์•ˆ๋ณด์ด๋Š” ์ง€ ํŒ๋‹จํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

์›ํ•˜๋Š” ์ด๋ฏธ์ง€๊ฐ€ ๋ณด์ผ ๊ฒฝ์šฐ (๋งˆ์ง€๋ง‰ ์š”์†Œ ์ด๋ฏธ์ง€) ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ๋กœ๋”ฉํ•˜๋Š” ๋™์ž‘์„ ๊ตฌํ˜„ํ•˜๋ฉด ์Šคํฌ๋กค ๋ฐ”๋ฅผ ๋๊นŒ์ง€ ์ด๋™์‹œ์ผฐ์„ ๊ฒฝ์šฐ, ๊ทธ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ๋กœ๋”ฉํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

if (item.isIntersecting) {
  let dataIndex = Number(item.target.dataset.index);
  // ๋งˆ์ง€๋ง‰ ์š”์†Œ์ธ์ง€ ์ฒดํฌ
  if (dataIndex === this.data.length - 1) {
    this.onNextPage();
  }
}

 

 

lazy loading

์ด๋ฏธ์ง€๊ฐ€ ๋กœ๋”ฉ๋˜๊ธฐ ์ „์— ๋”๋ฏธ ์ด๋ฏธ์ง€๋ฅผ ํ†ตํ•ด ํ™”๋ฉด ์š”์†Œ๋“ค์„ ๋ฐฐ์น˜ํ•œ ํ›„, ๋กœ๋”ฉ์ด ์™„๋ฃŒ๋œ ํ›„์— ๋”๋ฏธ ์ด๋ฏธ์ง€๋ฅผ ๋กœ๋”ฉ๋œ ์ด๋ฏธ์ง€๋กœ ๋ฐ”๊พธ๋ฉด UI๊ฐ€ ์ž์—ฐ์Šค๋Ÿฌ์›Œ์ง„๋‹ค.

`<li class="item" data-index=${idx}>
  <img src="https://via.placeholder.com/200x300" data-src=${cat.url}  alt=${cat.name} />
</li>`

 

์š”์†Œ์˜ dataset ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•œ๋‹ค.

img์˜ src ์†์„ฑ์„ ์ฒ˜์Œ์— ๋”๋ฏธ ๋ฐ์ดํ„ฐ๋กœ ๋„ฃ๊ณ  ๋กœ๋”ฉ์ด ์™„๋ฃŒ๋œ ํ›„ dataset์˜ src๋ฅผ ๋ถˆ๋Ÿฌ์™€ img์˜ src ์†์„ฑ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

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

 

 

 

 

 

๋งˆ๋ฌด๋ฆฌ


์˜ค๋Š˜ ๋ฐฐ์šด ๋‚ด์šฉ๋“ค์€ ์‹ค์ œ ๊ฐœ๋ฐœ์—์„œ ์ž์ฃผ ๋ณด์ด๊ณ  ์“ฐ์ด๋Š” ์ฝ”๋“œ๋“ค์„ ํ•™์Šตํ•œ ๊ฒƒ ๊ฐ™์•„์„œ ์œ ์ตํ–ˆ๋‹ค.

๊ณผ์—ฐ ๋‚ด๊ฐ€ ํ˜ผ์ž ์ง ๋‹ค๊ณ  ํ•˜๋ฉด ์ž˜ ํ•  ์ˆ˜ ์žˆ์„๊นŒ? ์•„์ง ๊ณผ์ œ๋ฅผ ์•ˆํ’€์–ด๋ด์„œ ๋ชจ๋ฅด๊ฒ ๋‹ค. ใ…Žใ…Ž ์ ์  ์ฝ”๋“œ๊ฐ€ ๋งŽ์•„์ง€๋‹ˆ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๋ถ€๋ถ„๋„ ๋งŽ์ด ์ƒ๊ธด๋‹ค.

๋ณต์Šต์ด ๊ผญ ํ•„์š”ํ•œ ๋ถ€๋ถ„์ธ ๊ฒƒ ๊ฐ™๋‹ค.

๊ฐ•์˜๊ฐ€ ์•ฝ๊ฐ„ ๋ฐ€๋ ค์žˆ๋Š”๋ฐ ๋ณต์Šต๋„ ํ•˜๋ ค๋ฉด... ์ฃผ๋ง์—๋„ ์—ด์‹ฌํžˆ ๋“ค์–ด์„œ ์ด๋ฒˆ ์ฃผ ๊ฐ•์˜๋Š” ๋‹ค ๋๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์•ผ๊ฒ ๋‹ค.