[TIL] 210928

Lee Syongยท2021๋…„ 9์›” 28์ผ
0

TIL

๋ชฉ๋ก ๋ณด๊ธฐ
41/204
post-thumbnail

๐Ÿ“ ์˜ค๋Š˜ ํ•œ ๊ฒƒ

  1. dispatchEvent() / ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง ๋ง‰๋Š” ๋ฐฉ๋ฒ• / event.preventDefault() / ์ด๋ฒคํŠธ ์œ„์ž„ / keydown๊ณผ keyup ๋น„๊ต / ์ปค์Šคํ…€ ๋ฐ์ดํ„ฐ ์†์„ฑ

  2. ๋‚ด๊ฐ€ ์ง  ์ฝ”๋“œ์™€ ๊ฐ•์˜ ๋‚ด์šฉ ๋น„๊ตยท๋ถ„์„ ๋ฐ ์ˆ˜์ • (์‡ผํ•‘ ๋ชฉ๋ก ์•ฑ ๋งŒ๋“ค๊ธฐ)


๐Ÿ“– ํ•™์Šต ์ž๋ฃŒ

  1. ๋“œ๋ฆผ์ฝ”๋”ฉ 'ํ”„๋ก ํŠธ์—”๋“œ ํ•„์ˆ˜ ๋ธŒ๋ผ์šฐ์ € 101' ๊ฐ•์˜

๐Ÿ“š ๋ฐฐ์šด ๊ฒƒ

1. DOM, CCSOM, Render Tree, Critical rendering path

1) ์‡ผํ•‘ ๋ชฉ๋ก ์•ฑ ๋งŒ๋“ค๊ธฐ

์ตœ์ดˆ ์ฝ”๋“œ๋Š” ์–ด์ œ TIL ์ฐธ๊ณ 
๊ฐ•์˜๋ฅผ ๋ณธ ํ›„ ๋‚ด ์ฝ”๋“œ์™€์˜ ์ฐจ์ด์ , ๋ฐฐ์šด ์  ์ •๋ฆฌ

(1) HTML ๋งˆํฌ์—…

  • ๋‚˜๋Š” input์„ ๋ณธ๋ฌธ์— ๋„ฃ์—ˆ๋Š”๋ฐ, ๊ฐ•์˜์—์„œ๋Š” input์„ ๋ณธ๋ฌธ์ด ์•„๋‹ˆ๋ผ footer์— ๋„ฃ์—ˆ๋‹ค.

  • ๋‚˜๋Š” ์‡ผํ•‘ ๋ชฉ๋ก๋“ค์ด ์ถ”๊ฐ€๋  ๋ณธ๋ฌธ์„ div๋กœ ์ง€์ •ํ•ด์ค€ ํ›„ javascript์—์„œ ๊ทธ ์•ˆ์˜ ๋งˆํฌ์—… ๋ชจ๋‘๋ฅผ ๋™์ ์œผ๋กœ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ๋Š”๋ฐ, ๊ฐ•์˜์—์„œ๋Š” ul๋กœ ์ง€์ •ํ•ด์ค€ ํ›„ li, div, span, button์„ html ๋ฌธ์„œ์—๋„ ๋ชจ๋‘ ์ ์–ด์ฃผ์—ˆ๋‹ค. (javascript ์ž‘์„ฑ ์‹œ ์ฐธ๊ณ  ์šฉ์ด์—ˆ์Œ, ๋งˆ์ง€๋ง‰์— ์ง€์šด๋‹ค)

(2) CSS ์Šคํƒ€์ผ๋ง

  • ๊ฐ•์˜์—์„œ๋„ ๋ฐ˜์‘ํ˜•์œผ๋กœ ๋งŒ๋“ค์ง€๋Š” ์•Š์•˜๋‹ค. ๋ฐ˜์‘ํ˜•์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‚˜ ๊ถ๊ธˆํ•ด์„œ ์ˆ˜์ •ํ•ด๋ดค๋‹ค. ๊ทผ๋ฐ ์ตœ๋Œ€ ํฌ๊ธฐ๋ฅผ ์ž‘๊ฒŒ ์žก์•„์„œ ํฌ๊ฒŒ ์˜๋ฏธ๊ฐ€ ์—†๋Š” ๊ฑฐ ๊ฐ™๋‹ค. vw, vh๋ฅผ ์‚ฌ์šฉํ•ด๋ด„.

(3) JavaScript ๋™์ ์œผ๋กœ

  • ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ํ•จ์ˆ˜์˜ ์ด๋ฆ„ ์•ž์—๋Š” ํ†ต์ƒ์ ์œผ๋กœ on์„ ๋ถ™์ธ๋‹ค. ex) onAdd, onDelete, onClick ๋“ฑ

  • ๋‚˜๋Š” add ํ•จ์ˆ˜์— ์ƒˆ๋กœ์šด ์š”์†Œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ๊นŒ์ง€ ์ „๋ถ€ ์ญ‰ ์ผ๋Š”๋ฐ, ๊ฐ•์˜์—์„œ๋Š” createItem ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋”ฐ๋กœ ๋นผ๋ƒˆ๋‹ค.

  • ๋‚˜๋Š” ํœด์ง€ํ†ต ์•„์ด์ฝ˜์„ ํด๋ฆญํ•ด์„œ ๋ชฉ๋ก์ด ์‚ญ์ œ๋˜๋ฉด input ์•ˆ์˜ ๊ธ€์ž๋„ ์‚ญ์ œ๋˜๋Š” ๊ฒƒ๊นŒ์ง€๋งŒ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ, ๊ฐ•์˜์—์„œ๋Š” ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ์ปค์„œ๊ฐ€ input ์ฐฝ์— ์ƒ๊ฒจ์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐ”๋กœ ๊ธ€์ž๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค. document.querySelector('input').focus() ์ถ”๊ฐ€
    document.querySelector('input').setAttribute('autoFocus') ์•„๋‹˜ ์ฃผ์˜

  • ๋‚˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ createElement๋ฅผ ์ด์šฉํ•ด ์ƒˆ๋กญ๊ฒŒ ์š”์†Œ๋ฅผ ๋งŒ๋“ค ๋•Œ๋งˆ๋‹ค style ์†์„ฑ์„ ์ด์šฉํ•ด ์Šคํƒ€์ผ์„ ์ถ”๊ฐ€ํ•œ ๋ฐ˜๋ฉด, ๊ฐ•์˜์—์„œ๋Š” ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“  ์š”์†Œ์— class๋ฅผ ๋ถ€์—ฌํ•ด์„œ ๋ฏธ๋ฆฌ class๋งˆ๋‹ค ์ •์˜ํ•ด๋‘” CSS ์Šคํƒ€์ผ๋ง์„ ์ƒˆ๋กœ ๋งŒ๋“  ์š”์†Œ์— ์ž…ํ˜”๋‹ค.

  • ๋‚˜๋Š” ๋ชฉ๋ก์„ ์ด๋ฃจ๋Š” ์š”์†Œ๋“ค ์ค‘ ์ œ์ผ ์ƒ์œ„ ์š”์†Œ๋งŒ์„ createElement๋ฅผ ์ด์šฉํ•ด ๋งŒ๋“  ํ›„ ๊ทธ ๋‹ค์Œ๋ถ€ํ„ด innerHTML์„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ, ๊ฐ•์˜์—์„œ๋Š” ๋ชฉ๋ก์„ ์ด๋ฃจ๋Š” ์š”์†Œ๋“ค ์ „๋ถ€๋ฅผ createElement๋ฅผ ์ด์šฉํ•ด ๋งŒ๋“  ํ›„ appendChild๋กœ ์š”์†Œ ๋ฐ‘์— ์š”์†Œ๋ฅผ ๋„ฃ์–ด์คฌ๋‹ค.

  • createElement ํ•จ์ˆ˜๊ฐ€ '๋ชฉ๋ก'์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งˆ์ง€๋ง‰์— ๊ผญ return์„ ์จ์ค˜์•ผ ํ•œ๋‹ค !

  • ๊ฐ•์˜์—์„œ๋Š” ๋ชฉ๋ก๋“ค์ด ํ™”๋ฉด์˜ ๋†’์ด๋ณด๋‹ค ๊ธธ์–ด์ง€๋ฉด ์Šคํฌ๋กค์— ์˜ํ•ด ์ž๋™์œผ๋กœ ๊ฐ€์žฅ ์ตœ๊ทผ์— ์ถ”๊ฐ€ํ•œ ๋ชฉ๋ก์ด ๋ณด์—ฌ์ง€๋„๋ก scrollIntoView๋ฅผ ์ ์šฉํ–ˆ๋‹ค.

๐Ÿ“Œ ์ˆ˜์ •ํ•œ ์ฝ”๋“œ

๐Ÿ”Ž HTML

<html>
  <body>
    <section>
      <header>
        <h1>Shopping List</h1>
      </header>
      <ul class="items"></ul>
      <footer>
        <input class="footer-input" type="text">
        <button class="footer-addBtn"><i class="fas fa-plus-circle"></i></button>
      </footer>
    </section>
  </body>
<html>

๐Ÿ”Ž CSS

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

button {
  border-style: none;
  background-color: transparent;
  cursor: pointer;
  color: rgb(82, 82, 82);
}

button:hover {
  transform: scale(1.1);
  color: rgb(106, 173, 151);
  transition: all 300ms;
}

body {
  font-family: "Gowun Batang", serif;
  color: rgb(65, 65, 65);
}

section {
  /* ์„น์…˜ ๋„ˆ๋น„ */
  width: 80vw;
  min-width: 300px;
  max-width: 500px;

  margin: 100px auto;
  border-radius: 10px;
  -webkit-box-shadow: 0 0 10px gray;
  box-shadow: 0 0 10px gray;
}

header {
  /* ํ—ค๋” ๋†’์ด */
  height: 70px;

  text-align: center;
  background: linear-gradient(70deg, rgb(196, 202, 255), rgb(220, 255, 255));
  border-radius: 10px 10px 0 0;
}

h1 {
  line-height: 2.2;
}

.items {
  /* ul ๋†’์ด */
  height: 50vh;
  min-height: 300px;

  background: rgb(245, 245, 245);
  overflow: auto;
  padding: 10px;
}

.item-row {
  list-style: none;
  padding: 10px 20px 0 20px;
}

.item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 10px;
}

.far {
  font-size: 1.2em;
}

.item-line {
  width: 100%;
  height: 1px;
  background-color: rgb(65, 65, 65);
  margin: 0 auto;
}

footer {
  background: linear-gradient(70deg, rgb(196, 202, 255), rgb(220, 255, 255));
  border-radius: 0 0 10px 10px;
}

.footer-input {
  /* input ๋„ˆ๋น„ & ๋†’์ด */
  width: 100%;
  height: 40px;

  font-family: "Gowun Batang", serif;
  padding: 10px 10px;
  border-style: none;
  color: rgb(48, 48, 48);
}

.footer-input:focus {
  outline: none;
  -webkit-box-shadow: inset 0px 0px 5px 2px #b6b6b6;
  box-shadow: inset 0px 0px 5px 2px #b6b6b6;
}

.footer-addBtn {
  display: block;
  margin: 0 auto;
  font-size: 50px;
  padding: 10px 0 5px 0;
}

::selection {
  background-color: rgb(127, 197, 164);
  color: white;
}

๐Ÿ”Ž javascript

const input = document.querySelector('input');
const addBtn = document.querySelector('.footer-addBtn');
const items = document.querySelector('.items');

// input ํ…์ŠคํŠธ ๊ฐ’ ( input.value )

function onAdd () {
  if (input.value === '') {
    return;
  } else {
    const itemRow = createItem();
    items.appendChild(itemRow);
    itemRow.scrollIntoView();
    input.value = '';
    input.focus();
  }
}

function createItem () {
  const itemRow = document.createElement('li');
  itemRow.classList.add('item-row');

  const item = document.createElement('div');
  item.classList.add('item');

  const itemName = document.createElement('span');
  itemName.classList.add('item-name');
  itemName.innerHTML = input.value;

  const DeleteBtn = document.createElement('button');
  DeleteBtn.innerHTML = '<i class="far fa-trash-alt">';
  DeleteBtn.classList.add('item-deleteBtn');
  DeleteBtn.addEventListener('click', () => items.removeChild(itemRow));

  const itemLine = document.createElement('div');
  itemLine.classList.add('item-line');

  item.appendChild(itemName);
  item.appendChild(DeleteBtn);

  itemRow.appendChild(item);
  itemRow.appendChild(itemLine);
  console.log(itemRow);

  return itemRow;
}

addBtn.addEventListener('click', () => onAdd());

input.addEventListener('keyup', e => {
  if (e.key === "Enter") {
    onAdd();
  } else {
    return;
  }
});

2. ์ด๋ฒคํŠธ(Events)

1) ํ•„๊ธฐ

2) ์‹ค์Šต - ์‡ผํ•‘ ๋ชฉ๋ก ์•ฑ ๊ฐœ์„ ํ•˜๊ธฐ

(1) ์ด๋ฒคํŠธ ์œ„์ž„ ์‘์šฉํ•˜๊ธฐ ( innerHTML & data-id )

DeleteBtn.addEventListener('click', () => items.removeChild(itemRow)); ๋ถ€๋ถ„ ์ˆ˜์ •

โ€ป ์—ฌ๊ธฐ์„œ๋Š” data-id์˜ ๊ฐ’์œผ๋กœ ๊ธ€๋กœ๋ฒŒ ์ˆซ์ž ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ–ˆ์ง€๋งŒ, ์›๋ž˜ UUID๋‚˜ ์˜ค๋ธŒ์ ํŠธ์˜ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•ด ๊ณ ์œ ํ•œ ์•„์ด๋””๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

const input = document.querySelector('input');
const addBtn = document.querySelector('.footer-addBtn');
const items = document.querySelector('.items');

function onAdd () {
  if (input.value === '') {
    return;
  } else {
    const itemRow = createItem();
    items.appendChild(itemRow);
    itemRow.scrollIntoView();
    input.value = '';
    input.focus();
  }
}

// โ— inneHTML ์ด์šฉํ•ด์„œ '์ด๋ฒคํŠธ ํƒ€๊นƒ'๊ณผ '์ง€์›Œ์งˆ ๋Œ€์ƒ'์— ๊ฐ™์€ data-id ๋ถ€์—ฌํ•˜๊ธฐ
let id = 0

function createItem () {
  const itemRow = document.createElement('li');
  itemRow.classList.add('item-row');

  itemRow.setAttribute('data-id', id);
  itemRow.innerHTML = `
    <div class="item">
      <span class="item-name">${input.value}</span>
      <button class="item-deleteBtn"><i class="far fa-trash-alt" data-id="${id}"></i></button>
    </div>
    <div class="item-line"></div>
  `;

  id++;

  return itemRow;
}

addBtn.addEventListener('click', () => onAdd());

input.addEventListener('keydown', e => {
  if (e.key === "Enter") {
    onAdd();
  } else {
    return;
  }
});

items.addEventListener('click', event => {
  const id = event.target.dataset.id;
  if (id) { // = event.target์˜ dataset์— id๊ฐ€ ์žˆ์œผ๋ฉด
    const toBeDeleted = document.querySelector(`.item-row[data-id="${id}"]`);
    toBeDeleted.remove();
  }
});

(2) form ํƒœ๊ทธ ์ด์šฉํ•ด submit ์ด๋ฒคํŠธ ๋“ฑ๋กํ•˜๊ธฐ

  • keydown, click ๋Œ€์‹  submit ์ด์šฉ
<form class="footer-form">
  <input class="footer-input" type="text">
  <button type="submit" class="footer-addBtn"><i class="fas fa-plus-circle"></i></button>
</form>
const form = document.querySelector('.footer-form');

form.addEventListener('submit', event => {
  event.preventDefault();
  onAdd();
});
profile
๋Šฅ๋™์ ์œผ๋กœ ์‚ด์ž, ํ–‰๋ณตํ•˜๊ฒŒ๐Ÿ˜

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