dispatchEvent() / ์ด๋ฒคํธ ๋ฒ๋ธ๋ง ๋ง๋ ๋ฐฉ๋ฒ / event.preventDefault() / ์ด๋ฒคํธ ์์ / keydown๊ณผ keyup ๋น๊ต / ์ปค์คํ ๋ฐ์ดํฐ ์์ฑ
๋ด๊ฐ ์ง ์ฝ๋์ ๊ฐ์ ๋ด์ฉ ๋น๊ตยท๋ถ์ ๋ฐ ์์ (์ผํ ๋ชฉ๋ก ์ฑ ๋ง๋ค๊ธฐ)
์ต์ด ์ฝ๋๋ ์ด์ TIL ์ฐธ๊ณ
๊ฐ์๋ฅผ ๋ณธ ํ ๋ด ์ฝ๋์์ ์ฐจ์ด์ , ๋ฐฐ์ด ์ ์ ๋ฆฌ
๋๋ input์ ๋ณธ๋ฌธ์ ๋ฃ์๋๋ฐ, ๊ฐ์์์๋ input์ ๋ณธ๋ฌธ์ด ์๋๋ผ footer์ ๋ฃ์๋ค.
๋๋ ์ผํ ๋ชฉ๋ก๋ค์ด ์ถ๊ฐ๋ ๋ณธ๋ฌธ์ div๋ก ์ง์ ํด์ค ํ javascript์์ ๊ทธ ์์ ๋งํฌ์ ๋ชจ๋๋ฅผ ๋์ ์ผ๋ก ์๋ก ๋ง๋ค์ด ์ฃผ์๋๋ฐ, ๊ฐ์์์๋ ul๋ก ์ง์ ํด์ค ํ li, div, span, button์ html ๋ฌธ์์๋ ๋ชจ๋ ์ ์ด์ฃผ์๋ค. (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;
}
});
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();
}
});
<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();
});