Vanilla JS로 댓글 기능이 있는 게시판 만들기_3일차
🧱 3일차 구현 내용
3일차에 목표로 했던 부분이다! 그리고 드디어 성공했다😎
list li에 클릭이벤트 걸기
1-1. li를 클릭시 댓글 영역이 slideDown 효과와 함께 나타나고 다시 클릭하면 slideUp 효과와 함께 사라진다.
삽질 n시간만에 드디어 해결! 그래서 오늘은 어떤 문제가 있어서 어떻게 해결했는지를 간략하게 써보려고 한다.
문제1
listLis.forEach(function(listLi){
listLi.addEventListener('click', function(event){
// .contains() : class의 유무를 확인
if (event.target.replyBox.classList.contains('show')) {
event.target.replyBox.classList.remove('show');
} else {
event.target.replyBox.classList.add('show');
}
});
});
내가 원하는 것은 li가 클릭되었을때 이벤트를 발생시키고 싶은 것이었다. 처음에는 for문을 사용해서 각각의 모든 li에 이벤트를 걸어주려고 했는데, 아무리 생각해봐도 이 방법은 아닌것같았다. 그래서 다른 방법을 찾아본 것이 이벤트 위임이었다. 이부분에 대한 내용은 다른분들이 작성하신 글을 참고해 내가 이해한 대로 정리했다.
(https://takeknowledge.tistory.com/32)
(https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/)
이벤트 버블링 : 특정 화면 요소에서 이벤트가 발생했을때 해당 이벤트가 더 상위의 화면 요소들로 전달되어 가는 특성
이벤트 캡처링 : 이벤트 버블링과는 반대로 상위 요소에서 하위 요소로 이벤트가 전파되는 방식
event.stopPropagation() : 이벤트가 전파되는 것을 막는 API. 버블링의 경우 클릭한 요소에만 이벤트를 발생시키고 상위요소로 이벤트가 전달되는 것을 막음. 캡처링의 경우에는 클릭한 요소의 최상위 요소의 이벤트만 동작하게 하고 하위로 이벤트를 전달하지 않게 함.
이벤트 위임 : 하위 요소에 개별적으로 이벤트를 걸지 않고 상위 요소에서 하위 요소의 이벤트를 제어하는 방식
그래서 각각의 li에 이벤트를 주는 것이 아니라 li의 상위요소인 ul에 이벤트를 주고, 클릭한 요소가 li라면 이벤트를 발생하게 하는 방식으로 내용을 정리했다.
list.addEventListener('click', function(event){
// li 이외의 요소가 클릭되면 함수를 빠져나가게 함 = 아무것도 실행하지 않음
if (event.target.tagName != 'LI') return;
// 클릭된 요소에 show class가 있다면
if (event.target.classList.contains('show')) {
event.target.classList.remove('show');
console.log('remove');
} else {
event.target.classList.add('show');
console.log('add');
}
});
.tagName : 요소의 태그명을 가져온다(HTML의 경우 대소문자를 무시하고 대문자로만 이루어진 값을 가져온다)
문제2
내가 짠 코드는 event.target을 통해 클릭된 li에 특정한 class가 붙고, 다시 클릭했을때 class가 사라지는 토글 형태였다. 게시글이 한개일 경우에는 add - remove 순으로 잘 동작했는데 게시글이 2개 이상일때부터 문제가 발생했다.
![](https://blog.kakaocdn.net/dn/dLA4Z4/btrTa58OMyf/sBDxmujM4XKnOcDTAvkkxK/img.png)
게시글이 2개일 경우
-> 클릭될 때마다 add/remove가 함께 발생했다. 그래서 댓글영역이 아예 열리지 않는 것처럼 보였다.
![](https://blog.kakaocdn.net/dn/exH7Va/btrS7JZRCws/DNQX6oH6pLJXJug63fR130/img.png)
게시글이 3개일 경우
-> 클릭시에 댓글 영역이 보였다. 하지만 이벤트가 한번만 실행되는 것이 아니라 add-remove-add가 동시에 발생되어 댓글 영역이 열리는 거였다.
게시글이 늘어나면 늘어날수록 이벤트의 개수도 함께 늘어났다. event.target으로 클릭 이벤트가 발생한 li 하나만을 가져오려고 했는데, 콘솔을 확인해보니 이벤트가 발생한 li를 전체 li의 개수만큼 가져오는것이었다. 그래서 구글링을 하다 나와 비슷한 문제라고 생각되는 글을 발견했다. (https://blog.sogoagain.com/posts/2020/register-the-same-event-listener-only-once/)
해당 글의 내용은 동일한 이벤트 리스너가 중복 등록 되었기때문에 생긴 문제와 해결방법이었다.
EventTarget.addEventListener()는 동일한 파라미터를 갖는 리스너가 동일한 eventTarget에 중복되어 등록된다면 중복된 것들은 제거되고 오직 하나만 등록된다. 그러나 여기에서 콘솔이 중복 출력되는 이유는, 익명 함수로 이벤트 리스너를 등록했기 때문이다. 자바스크립트에서는 함수도 레퍼런스를 갖는 객체인데 동일한 레퍼런스를 갖는 이벤트 리스너가 여러번 등록된다면 중복 처리되어 하나만 남게 된다. 그런데 여기에서 익명함수로 작성된 이벤트 리스너는 이벤트에 대해 등록될때마다 새로운 객체로 생성된다. 즉 5번 등록된 리스너의 레퍼런스는 모두 다 다르기 때문에 중복처리가 되지 않고 5개가 모두 등록되어버린다는 것이다.
그래서 나는 익명함수가 아니라 별개의 함수를 선언해 호출해보기로 했다.
list.addEventListener('click', liClick);
function liClick() {
if (event.target.tagName != 'LI') return;
if (event.target.classList.contains('show')) {
event.target.classList.remove('show');
} else {
event.target.classList.add('show');
}
};
익명함수가 아니라 별개의 함수를 선언하여 list가 클릭되면 liClick 함수가 실행되고 클릭된 요소event.target가 li가 아니라면 아무것도 실행하지 않고, 그 이외의 경우에는 클릭된 li에 show class가 있는지 판단해 클래스를 토글처럼 툽텼다 뗐다 해주었다. 슬라이드 효과는 css로 처리했다.
❓ 궁금한 점
다만 작업하면서 궁금한 점이 생겼는데, liClick() 함수에서 return이 아니라 continue나 break를 사용하려고 했더니 Jump target cannot cross function boundary. 라는 에러가 발생했다. 이럴때는 continue나 break를 사용하면 안되는걸까? 두개의 사용법을 다시 한번 공부해봐야겠다.
참고
https://takeknowledge.tistory.com/32
https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/
https://blog.sogoagain.com/posts/2020/register-the-same-event-listener-only-once/
'study > JavaScript' 카테고리의 다른 글
[자바스크립트 딥다이브] 05. 표현식과 문 (0) | 2022.12.10 |
---|---|
[자바스크립트 딥다이브] 04. 변수 (0) | 2022.12.10 |
Vanilla JS로 댓글 기능이 있는 게시판 만들기_2일차 (0) | 2022.12.08 |
Vanilla JS로 댓글 기능이 있는 게시판 만들기_1일차 (0) | 2022.12.08 |
Javascript 스터디(1주차) (1) | 2022.12.08 |