블랙커피 스터디1 문벅스 step1 DOM조작과 이벤트 핸들링 회고
🎯 step1 요구사항 - 돔 조작과 이벤트 핸들링으로 메뉴 관리하기
- 에스프레소 메뉴에 새로운 메뉴를 확인 버튼 또는 엔터키 입력으로 추가한다.
- 메뉴가 추가되고 나면, input은 빈 값으로 초기화한다.
- 사용자 입력값이 빈 값이라면 추가되지 않는다.
- 메뉴의 수정 버튼을 눌러 메뉴 이름 수정할 수 있다.
- 메뉴 수정시 브라우저에서 제공하는
prompt
인터페이스를 활용한다.
- 메뉴 수정시 브라우저에서 제공하는
- 메뉴 삭제 버튼을 이용하여 메뉴 삭제할 수 있다.
- 메뉴 수정시 브라우저에서 제공하는
confirm
인터페이스를 활용한다.
- 메뉴 수정시 브라우저에서 제공하는
- 총 메뉴 갯수를 count하여 상단에 보여준다.
- 추가되는 메뉴의 아래 마크업은
<ul id="espresso-menu-list" class="mt-3 pl-0"></ul>
안에 삽입해야 한다.
form eventListener - 엔터 || 버튼 클릭 이벤트 감지하기
미션 요구사항중,
에스프레소 메뉴에 새로운 메뉴를 확인 버튼 또는 엔터키 입력으로 추가한다.
라는 기능이 있어 버튼 클릭과 엔터키 입력을 각각 걸어줘야하나 고민하던중 한번에 관리할 수 있는 방법을 찾게 되었다.
<form id="espresso-menu-form">
<div class="d-flex w-100">
<label for="espresso-menu-name" class="input-label" hidden>
에스프레소 메뉴 이름
</label>
<input
type="text"
id="espresso-menu-name"
name="espressoMenuName"
class="input-field"
placeholder="에스프레소 메뉴 이름"
autocomplete="off"
/>
<!-- type은 꼭 submit으로 !! -->
<button
type="submit"
name="submit"
id="espresso-menu-submit-button"
class="input-submit bg-green-600 ml-2"
>
확인
</button>
</div>
</form>
const $form = document.querySelector("#espresso-menu-form");
// form에 eventListener 걸어주기
$form.addEventListener("submit", (e) => {
e.preventDefault();
if (!$input.value) {
alert("값을 입력하세요.");
} else {
onAddMenuClick();
}
});
이런식으로 form 자체에 eventListener를 걸어주면 button을 클릭하는것과 엔터를 치는 이벤트를 중복해서 등록할 필요 없다. 원샷투킬이 가능해진다!
단, 이때 주의할점은 button의 type이 꼭 submit이여야한다. <button type="button">
으로 마크업하면 백날 이벤트리스너 등록해봤자 소용이 없다 ..
(+ if/else문으로 작성하지 않고, if문에서 조건이 일치하지 않으면 return시키고 다음 라인에 onAddMenuClick
를 호출하는 식으로 작성할지 고민했는데 현재 코드에서는 그냥 if/else문이 더 깔끔한 것 같아서 일단은 그렇게 작성했다. 혹시 이 부분에 대해 피드백이 있으면 수정해야겠다.)
이벤트 위임 - 효율적으로 이벤트를 관리하기
요구사항중 메뉴를 수정하거나 삭제할 수 있는 기능을 만들어야 했는데, 처음에는 querySelector로 각각의 수정과 삭제 버튼을 찾은 다음 각 요소마다 이벤트리스너를 등록하려 했었다. 그런데 조금 비효율적인 것 같아서 찾아보던 중 이벤트 위임을 사용하면 조금더 효율적으로 코드를 짤 수 있어 적용해보았다.
<!-- 수정, 삭제 버튼을 클릭시 이벤트를 감지해야한다. -->
<span class="w-100 pl-2 menu-name">${$input.value}</span>
<button
type="button"
class="bg-gray-50 text-gray-500 text-sm mr-1 menu-edit-button"
>
수정
</button>
<button
type="button"
class="bg-gray-50 text-gray-500 text-sm menu-remove-button"
>
삭제
</button>
</span>
$menuList.addEventListener("click", (e) => {
// 수정 || 삭제를 구분하기 위해 innerText를 썼는데,
// 더 좋은 방법이 있을지 궁금하다. 👀
if (e.target && e.target.innerText == "수정") {
const result = window.prompt("메뉴명을 수정하세요.");
e.target.parentNode.firstElementChild.innerText = result;
}
if (e.target && e.target.innerText == "삭제") {
window.confirm("정말 삭제하시겠습니까?") &&
$menuList.removeChild(e.target.parentNode);
}
}
부모 요소에 이벤트리스너를 적용하면 굳이 하나하나 적용 시켜줄 필요 없이 일타쌍피가 가능하다. 🔥
MutationObserver() - DOM 변경 감지하기
미션 요구 사항중 등록된 메뉴(아이템)의 갯수를 적어야 하는 문제가 있어서 알아보던 중 MutationObserver를 발견했다. 처음엔 변경을 감지하려는 DOM에다가 change 이벤트리스너를 등록하려 했는데, change 이벤트리스너는 폼 종류(예: input, selectbox)에만 등록이 돼서 MutationObserver를 활용하게 되었다.
const observer = new MutationObserver((mutationsList) => {
const count = mutationsList[0].target.children.length;
$menuCount.innerHTML = `총 ${count}개`;
});
observer.observe($menuList, {
attributes: false,
childList: true,
subtree: false,
});
observer.observe
뒤에 있는 객체는 변경을 감지할때 속성을 적는건데, 하위 요소의 속성 변경이나 노드의 내용이 변경되었을때 감지하는 등 다양한 옵션을 적을 수 있었다. 나는 자식 노드의 갯수만 체크하면 돼서 childList
만 true로 값을 줬다.
총 아이템의 갯수가 잘 변한다. 👍✨
MutationObserver를 사용하지 않는 방법으로는, 자식 노드의 갯수를 카운팅하는 함수를 등록/삭제 이벤트 감지마다 호출하는 방법이 있을텐데 이번엔 MutationObserver를 사용해봤다. 이것도 뭐가 옳고 그른지는 잘 모르겠어서 피드백이 있으면 수정해야겠다. (피드백 적극 환영합니다.)
마치며
블랙커피 스터디에 들어간 이유가 회사에서는 리액트로만 개발하고, 바닐라 자바스크립트에서는 나의 지식을 빈약함을 느껴.. 바닐라 자바스크립트 스킬을 향상시키고 싶어 들어갔는데 좋은 선택인 것 같았다. 첫번째 미션은 비교적 말랑말랑하게 해결할 수 있어 안심이였다. (월요일 오후에 시작했는데 기한 못맞춰 제출할까 쫄았다 .. ^^ㅠ) 하지만.. 미션은 완료했지만 내가 코드를 잘 짠건지는 모르겠다. 항상 코드를 짤때마다 느끼는 불안함.. 뭔지 아시죠? 그냥 <어떻게든 굴러가기만 하는 코드>를 제출해버린것 같아서 두렵지만.. 오랜만에 바닐라 자바스크립트로 환기를 시켜줘서 좋았다. 앞으로도 바닐라 자바스크립트를 열심히 공부해야지..🔥
Author And Source
이 문제에 관하여(블랙커피 스터디1 문벅스 step1 DOM조작과 이벤트 핸들링 회고), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@yukyung/블랙커피-스터디1-회고저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)