사람들이 언어에 적응하기 위해 가장 많이 만드는 투두리스트를 자바스크립트로 만들어보았다. 리액트로는 hook을 이용해서 쉽게 만들 수 있는데 자바스크립트로 만들 생각을 하니 앞이 깜깜했다. 그래서 유데미에서 '블랙커피 Vanila JS 문벅스 카페 메뉴 앱 만들기' 인강을 섹션 2까지 들었다. 많이 듣지 않았는데도 자바스크립트로 DOM 조작을 어떻게 할지 방향을 잡는 데 큰 도움이 되었다.
강의에서 DOM 조작을 많이 하기 때문에 간편하게 선택자를 파라미터로 받아서 querySelector를 사용하는 $ 함수를 만든다. 그걸 보고 querySelectorAll도 마찬가지로 쉽게 가져올 수 있도록 $all 함수를 응용해서 만들었다. 덕분에 매우 간편하게 DOM 조작을 할 수 있었다.
const $ = (selector) => document.querySelector(selector);
const $all = (selector) => document.querySelectorAll(selector);
HTML 코드
HTML 구조부터 공유하면 다음과 같다. id 가 특수성이 높아 유지관리가 어려워 사용을 지양해야 한다고 들었지만 투두리스트라 구조가 간단해서 굳이 그 부분까진 신경을 안써도 될 것 같아서 id를 썼다. 나중에 규모가 큰 프로젝트를 진행할 땐 주의하자!
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Todos</title>
<link rel="stylesheet" href="./index.css" />
<script defer src="./index.js"></script>
</head>
<body>
<main class="wrapper">
<header>
<h1 class="title">Todos</h1>
</header>
<section class="main">
<div id="inputNewItemSection">
<input
id="newItem"
type="text"
placeholder="What do you need to do?"
/>
<button id="checkIcon" class="invisible">∨</button>
</div>
<div>
<ul id="todoItemList">
<!-- item 이 추가되는 영역 -->
</ul>
<div id="itemBottomSection" class="invisible">
<span id="itemCount"></span>
<div id="filterSection">
<button id="allBtn">All</button>
<button id="activeBtn">Active</button>
<button id="completedBtn">Completed</button>
</div>
</div>
</div>
</section>
</main>
</body>
</html>
자바스크립트 - 항목 추가하는 매서드
예전에 자바스크립트를 공부할 때 'createElement'와 'appendChild', 그리고 'innerHTML'로 항목 추가하는 법을 배웠었다. 그런데 인터넷 강의에서는 insertAdjacentHTML이라는 매서드를 사용해서 항목을 추가했다. 이전에 전자의 방법을 썼었으니 이번에는 새롭게 인터넷에서 배운 매서드를 사용해보았다. 추가로 항목을 추가할 수 있는 매서드가 더 있는지 궁금해서 찾아보니 insertBefore가 있었다. 항목 추가하는 매서드들을 간단하게 정리해보자!
1. createElement와 appendChild()
Document.createElement(tagName) 은 HTML 요소를 만드는 매서드이다. 상단 예제에서 li 태그를 생성하여 newItem이라는 변수에 담았다.
Node.appendChild()는 파라미터를 특정한 부모 Node의 자식 노드 리스트 중 마지막 자식으로 만드는 매서드이다. 예제에서 newItem 을 쉽게 확인할 수 있도록 textContent로 '아이템'이라는 글자를 추가하고, list에 newItem을 자식으로 넣어주었다. Node에는 파라미터의 상위 요소가 됐으면 하는 부모의 태그를 넣으면 된다. Node에는 body도 입력할 수 있다.
2. insertAdjacentHTML()
insertAdjacentHTML(position, html)은 두 가지의 파라미터를 받는다. position에 beforebegin, afterbegin, beforeend, afterend 중 하나를 입력하여 HTML 콘텐츠가 삽입되어야 하는 요소의 위치를 지정할 수 있다. html에는 삽입할 html 콘텐츠를 입력하면 된다.
const addNewItem = (newItemContent) => {
$("#todoItemList").insertAdjacentHTML(
"---position 속성 입력---",
addNewItemTemplate(newItemContent)
);
};
- 'beforebegin': 기존 요소 바로 앞에 새 HTML 콘텐츠를 삽입
- 'afterbegin': 새 HTML 콘텐츠를 기존 요소의 첫 번째 자식으로 삽입
- 'beforeend': 새 HTML 콘텐츠를 기존 요소의 마지막 자식으로 삽입
- 'afterend': 기존 요소 바로 뒤에 새 HTML 콘텐츠를 삽입
설명만 봐서는 position에 따라 결과가 어떻게 달라지는지 알아보기 힘들다. 그래서 네 가지를 각각 입력해서 결과를 가져왔다. #todoItemList는 ul 태그인 것을 기억하고 결과를 살펴보자.
- 'beforebegin': 기존 요소 바로 앞에 새 HTML 콘텐츠를 삽입
li 태그가 ul 태그 위에 생성되었다. li 태그와 ul 태그는 형제관계다.
li가 추가한 순서대로(1->2->3) 배치되었다.
- 'afterbegin': 새 HTML 콘텐츠를 기존 요소의 첫 번째 자식으로 삽입
ul 태그 안에 li 태그가 생겼다. ul 태그는 부모, li 태그는 자식이다.
li가 생성된 순서의 역순으로 배치되었다.
- 'beforeend': 새 HTML 콘텐츠를 기존 요소의 마지막 자식으로 삽입
ul 태그 안에 li 태그가 생겼다. ul 태그와 li 태그는 부모-자식 관계다.
li가 생성한 순서대로 배치되었다.
- 'afterend': 기존 요소 바로 뒤에 새 HTML 콘텐츠를 삽입
ul 태그 아래에 li 태그가 생겼다. ul과 li는 형제관계이다.
li는 생성된 순서의 역순으로 배치되었다.
화면만 보았을 때 afterbegin과 afterend / beforebegin과 beforeend의 결과가 각각 같아보이지만 개발자 도구로 살펴보니 결과가 다르다는 걸 알 수 있다. 나는 ul 태그와 li 태그가 부모-자식관계가 되면서 나중에 추가한 항목이 상단에 배치되길 원해서 afterbegin 을 사용했다.
3. innerHTML
element.innerHTML 은 element 안에 html 코드를 넣어주는 매서드이다. element.innerText 와 자주 비교가 된다.
예제를 보면 innerText는 이름처럼 html 코드가 그대로 텍스트(문자열)로 반환된다. innerHTML도 이름대로 html 태그로 반환된다. 그러니 항목을 추가하고 싶다면 이런 식으로 같이 코드를 작성하면 된다.
const addNewItem = (newItemContent) => {
const newItem = document.createElement("li");
$("#todoItemList").appendChild(newItem);
newItem.innerHTML = `
<div clsas="todoContainer">
<input class="toggle" type="checkbox" />
<label class="itemContent">${newItemContent}</label>
<button class="removeBtn">X</button>
</div>
`;
};
아! innerHTML 은 잠재적인 보안 위험이 발생할 수 있다고 하니 사용을 하지 않는 게 좋다. 하단 링크 참고 요망!
Element.innerHTML - Web API | MDN
Element 속성(property) innerHTML 은 요소(element) 내에 포함 된 HTML 또는 XML 마크업을 가져오거나 설정합니다.
developer.mozilla.org
4. insertBefore
Node.insertBefore() 메소드는 상위 노드의 기존 노드 앞에 새 노드를 삽입한다. insertBefore는 newNode와 referenceNode 두 개의 파라미터를 받는다. newNode는 추가할 노드이고, referenceNode 는 참조 노드, 다시 말해 추가할 노드가 삽입이 될 기준이 된다.
const addNewItem = (newItemContent) => {
const list = $("#todoItemList");
const newItem = document.createElement("li");
list.insertBefore(newItem, list.childNodes[0]);
newItem.innerHTML = `<li class="todoItem">
<div clsas="todoContainer">
<input class="toggle" type="checkbox" />
<label class="itemContent">${newItemContent}</label>
<button class="removeBtn">X</button>
</div>
</li>`;
};
자바스크립트 코드 - 항목 추가 부분
내가 만든 투두리스트에서 항목을 추가하는 코드는 이렇다. 이미 만든 투두리스트를 공부하는 김에 앞에 적은 매서드로 계속 수정하면서 블로그 포스팅을 작성했다. 헥헥
const $ = (selector) => document.querySelector(selector);
const $all = (selector) => document.querySelectorAll(selector);
const addNewItemTemplate = (newItemContent) => {
return `<li class="todoItem">
<div clsas="todoContainer">
<input class="toggle" type="checkbox" />
<label class="itemContent">${newItemContent}</label>
<button class="removeBtn">X</button>
</div>
</li>`;
};
const addNewItem = (newItemContent) => {
$("#todoItemList").insertAdjacentHTML(
"afterbegin",
addNewItemTemplate(newItemContent)
);
};
$("#newItem").addEventListener("keypress", (e) => {
const newItemContent = $("#newItem").value;
if (!newItemContent) {
return;
}
if (e.key === "Enter") {
addNewItem(newItemContent);
addClass("#itemBottomSection", "visible");
addClass("#checkIcon", "visible");
updateItemCount();
$("#newItem").value = "";
}
});
항목이 추가되는 과정을 정리해보자.
1. 투두리스트를 새롭게 입력하는 input 창(#new-item)에 입력된 값이 변수 newItemContent에 담긴다.
2. 만약 input 창이 빈칸이라면 함수가 종료되기 때문에 항목이 추가되지 않는다.
3. 엔터를 눌렀을 때 addNewItem 함수와 addNewItemTemplate 함수가 실행되어 ul(#todoItemList)에 newITemContent 가 반영된 템플릿이 추가된다.
4. 항목 추가가 완료되면 input 창의 value 를 공백으로 만든다.
addClass 부분은 항목이 추가되었을 때 하단에 항목 개수와 필터 부분, 그리고 아래 화살표가 보여지게 하는 부분이다. 그리고 updateItemCount 함수는 항목이 추가될 때마다 항목 개수를 보여주는 부분이라 아이템 추가와 직접적인 관계는 없는 코드이다.
투두리스트 추가 결과물
아휴 포스팅 하나 작성하는데 엄청 오래 걸렸다 ㅠ_ㅠ 매서드 네 개 중 하나를 쏙 빼버릴까 하는 악마의 속삭임이 있었지만 꿋꿋하게 이겨냈다. 😙휴 ~! 에너지 충전을 한 뒤 항목 삭제와 수정에 대해서도 포스팅해야겠당~!! 끝!
'> 개발 > Javascript' 카테고리의 다른 글
[Javascript] geoloaction으로 내 위치 가져오기 (0) | 2023.05.19 |
---|---|
[Javascript] JSON과 open weather map API : 날씨 정보 가져오기 (0) | 2023.05.18 |
[Javascript] 실행 컨텍스트 (0) | 2023.03.15 |
[Javascript] 변수의 스코프, 호이스팅, TDZ (0) | 2023.03.14 |
[Javascript] parseInt()와 toString() (0) | 2023.03.10 |
댓글