<script>
//우선 버튼과 li들을 담고 있는 ul을 변수에 저장해준다
const btn = document.querySelector(".btn-select");
const langList = document.querySelector(".list-member");
btn.addEventListener("click", () => {
langList.classList.toggle("on");
btn.classList.add("on");
});
// btn-select에 textContent 삭제하고 li textContent 를 넣기
const li = langList.children;
for (let i = 0; i < li.length; i++) {
li[i].addEventListener("click", () => {
btn.textContent = li[i].textContent;
langList.classList.remove("on");
btn.classList.remove("on");
});
}
</script>
물론 이 방법도 좋지만, for문을 하나하나 돌아줘야한다는 단점이 있다. 이벤트 위임은 공통 조상에 이벤트 핸들러를 하나만 사용해도, 여러 요소를 한꺼번에 다룰 수 있는 것을 말하는데, 이벤트 위임을 사용하면 저렇게 자식요소들이 많아져도 하나하나 줄 필요가 없어서 좋다! 따라서 이벤트 위임을 활용해 코드를 좀 더 간결하게 짜보면 다음과 같다.
<script>
//btn-select를 클릭하면 list-member on 클래스 toggle로 달기
const btn = document.querySelector(".btn-select");
const langList = document.querySelector(".list-member");
btn.addEventListener("click", () => {
langList.classList.toggle("on");
btn.classList.add("on");
});
// btn-select에 textContent 삭제하고 li textContent 를 넣기
langList.addEventListener("click", () => {
btn.textContent = event.target.textContent;
langList.classList.remove("on");
btn.classList.remove("on");
});
</script>
물론 코드는 많이 간결해졌지만, 문제는 저 빨간색 부분을 클릭하면 발생하는 일이다.
히히히히... 죄다 불러와버렷~! 이런일이 발생한 이유는 내가 이벤트 위임을 활용해 해냈다는 것에 대한 뿌듯함이 내 눈을 가려버린것 ... 사실 저 부분은 버튼이 아닌 ul부분이기 때문에 event.target이 ul이 되어 ul에 있는 모든 textContent요소가 btn에 후두두둑 담겨버린다.
<script>
const btn = document.querySelector('.btn-select');
const list = document.querySelector(".list-member");
//추후 동적으로 데이터를 추가해줄 수 있도록 배열로 담아둔다
const arrLang = ['neo', 'Java', 'JavaScript', 'C#', 'C/C++'];
//forEach는 아이템을 순회하며 실행해준다
arrLang.forEach((item) => {
//우선 li,button 태그를 생성해준다
//button 태그를 사용해주는 이유는
//시맨틱한 마크업을 작성해주기 위함이다.
const li = document.createElement('li');
const btn = document.createElement('button');
// setAttribute는 선택한 요소(element)의 속성값을 정한다
//<button type="button"></button>
btn.setAttribute('type', 'button');
//btn의 textContent를 item에서 가져와 넣어준다
btn.textContent = item;
//li를 list의 자식 요소로 넣어준다
//btn을 li의 자식 요소로 넣어준다
list.appendChild(li);
li.appendChild(btn);
});
//toggle을 통해 btn을 클릭했을 때
//classList에 on이 없으면 추가해주고
//on이 있으면 제거해주는 기능
btn.addEventListener('click', () => {
btn.classList.toggle('on');
});
//여기가 중요한데, 이벤트 위임을 통해 처리해주는 대신
//ul이 선택되지 않도록,
//if 조건문을 달아서 event가 발생된 target의
//nodeName이 버튼일 경우에만 textContent를 넘겨주면 된다.
//list를 클릭하면 btn을 닫을 수있도록 remove로 클래스를 지워준다
list.addEventListener('click', (event) => {
if (event.target.nodeName === 'BUTTON') {
btn.textContent = event.target.textContent;
btn.classList.remove('on');
}
});
</script>
이와 같이 처리해준다면, 이벤트 위임을 이용하면서 동시에 예외 처리를 통해 버튼일 경우에만 동작이 되도록 처리해줘서 정상적으로 작동한다 :-) 야호
깨달은 점
👉 노드네임을 통해 예외처리 해주기!
👉 예외 처리는 확실히 혼자 발견하기 어려운 것 같다. 피드백의 중요성을 다시 한번 느꼈다.
다음에 해보고 싶은 시도
👉 이벤트 전파를 막는 event.stoppropagation()을 사용해보기