전에 HTML, CSS로 만들었던 드롭다운 구현과제에 이번에 배운 JS를 사용해 동작이 되도록 기능을 추가하는 과제를 새로 받았다.
일단 혼자서 구현해보고, 후에 김버그님의 강의를 참고하여 과제를 수정했다.
혼자했을 때는 단순히 드롭다운의 hide클래스를 remove, add해주면서 숨겼고, 리스트 아이템들의 textContet값을 받아와 셀렉트 값으로 넣어주었다.
<혼자구현 코드>
'use strict';
const selectButton = document.querySelector('.selectbox__button');
const selectListBox = document.querySelector('.selectbox__list');
const selectListButton = document.querySelectorAll('.list_button');
selectButton.addEventListener('click', () => {
selectListBox.classList.add('show');
})
selectListButton.forEach((item) => {
item.addEventListener('click', () => {
const language = item.textContent.trim();
selectButton.innerText = language;
})
})
selectListBox.addEventListener('click', (event) => {
if(event.target.nodeName == 'BUTTON') {
const language = event.target.textContent.trim();
selectButton.classList.add('selected');
selectButton.innerText = language;
selectListBox.classList.remove('show');
}
})
일단 이렇게 구현했을 때는 원하는 대로 동작이 잘되었다.
이후 김버그님 강의를 보는데, 이렇게 작성한 코드는 하수의 방식이라고 하셨다.
어느 부분의 코드였냐하면, 바로...
selectListBox.addEventListener('click', (event) => {
if(event.target.nodeName == 'BUTTON') {
const language = event.target.textContent.trim();
selectButton.classList.add('selected');
selectButton.innerText = language;
selectListBox.classList.remove('show');
}
})
여기서 리스트를 선택 후 다시 드롭다운을 닫아줄때, remove로 show태그를 지워준 코드이다. 이 코드는 바로 리스트를 선택하지 않고 그냥 드롭다운을 닫을 때, 즉 리스트가 아닌 다른 구역으로 포커스가 옮겨갔을 때 드롭다운이 닫히지 않는다는 문제점이 있다.
이 문제를 해결하기 위해, 좀 더 사용자를 생각한 코드를 짜기 위해 바로 blur event
를 이용해 줄 수 있다.
그래서 김버그님의 강의를 보고 다시 코드를 수정 후 실행시켜보았다.
'use strict';
const selectButton = document.querySelector('.selectbox__button');
const selectListBox = document.querySelector('.selectbox__list');
const selectListButton = document.querySelectorAll('.list_button');
selectButton.addEventListener('click', () => {
selectListBox.classList.remove('hide');
})
selectButton.addEventListener('blur', () => {
selectListBox.classList.add('hide');
})
selectListBox.addEventListener('click', (event) => {
if(event.target.nodeName == 'BUTTON') {
const language = event.target.textContent.trim();
selectButton.classList.add('selected');
selectButton.innerText = language;
}
})
그랬더니, 또 이상한 문제가 생겼다.
분명히 버그님의 강의에서는 리스트를 선택하면 선택된 리스트의 textContet가 셀렉트 된 후 드롭다운이 닫혔는데, 나는 드롭다운이 먼저 닫혀버리고 리스트 textContet를 셀렉트로 옮겨주는 이벤트가 일어나지 않았다.
먼저 강의영상을 보고 과제를 한 팀원들은 고민을 하다가 mousedown이벤트로 해결을 했지만, 여전히 의문이 남은 상태였다.
그래서 일단 유튜브를 뒤졌다. blur event javascript
키워드로 검색해 관련된 영상을 몇 개 봤고 대부분 간단한 튜토리얼 영상이었다. 딱 하나 내가 찾는 주제를 다룬 영상이 있었지만, 여기서도 mousedown을 통해 문제를 해결한 예시를 소개했다.
그래서 유튜브를 접고 구글링을 하러 갔다. 키워드는 blur event js stackoverflow
, blur event before click
을 넣고 검색했다. 스택오버플로우에서도 대부분 mousedown
을 해결방법으로 추천했고, 또는 setInterval
을 사용해 blur이벤트를 의도적으로 몇 초 뒤에 실행하도록 했다. 하지만 이런 방법들은 깔끔해보이지 않았다.
여기까지 내가 얻은 결론은 'blur이벤트가 click이벤트보다 항상 먼저 실행되기 때문에 blur이벤트 보다 먼저 실행되는 mousedown을 써서 해결해준다.'였다.
그래서 스택오버플로우를 접고 다시 김버그님의 강의 영상으로 가서 비슷한 이슈를 겪는 사람들이 있는지 댓글을 확인했다. 맨 마지막 댓글에서 같은 이슈를 겪은 사람을 찾았고 여기서 trasition duration이라는 새로운 관점(?)을 얻었다. 즉 blur
이벤트가 실행되는 시간이 mousedown
이벤트 후 mouseup
이벤트가 일어나는 시간보다 빨라서 두 이벤트가 일어나는 click
이벤트가 실행되기도 전에 blur
이벤트가 실행되어 셀렉트가 되지않은 채 드롭다운이 닫히는 것이었다.
그래서 김버그님이 강의영상에서 사용한 소스코드를 열어봤다.
JS코드는 진짜 똑같이 짜서 여기서는 도저히 문제를 찾을 수가 없었다. 개발자 도구 source탭에서 디버깅을 해봐도 전혀 모르겠더라. 그냥 이벤트 자체가 undefined으로 떠서 무슨 말인지 알 수가 없었다. (사실 디버깅은 많이 미숙하고, 혹시나하고 해본거다ㅎ)
그리고 팀원들 중 지훈님이 '뭔가 CSS에 문제가 있을 것 같은데 모르겠다'라고 한 말이 생각나서 CSS코드를 훑어봤다.
김버그님의 CSS 코드를 보다가 드롭다운 메뉴에 transition속성이 있는 걸 봤다.
(*김버그님은 드롭다운 메뉴의 초기 height 값을 0으로 주시고, show클래스가 붙었을 때 max-height 값을 280px로 설정해 컨트롤을 해주셨다.
여기서 transition을 메뉴가 보일 때 스르륵- 하고 부드럽게 열리는 효과를 주시려고 쓰신 것 같다.)
이때부터 뭔가 해결될 것같은 느낌을 받았다. 설마,, 이거 때문인가?
그래서 버그님의 CSS코드에서 transition을 없애고, 실행을 해봤더니,,, 역시나 팀원들과 내가 겪은 이슈가 똑같이 발생했다.
그리고 혹시나 해서 내 코드도 버그님처럼 CSS를 살짝 수정한 후 transition값을 넣어 실행 시켰더니,,, 원하는 대로 잘 동작이 되었다.
.selectbox__list {
max-height: 0;
/* border: 1px solid #c4c4c4; */
/* padding: 5px 8px; */
overflow: hidden;
border-radius: 10px;
font-size: 14px;
font-weight: 400;
line-height: 16.41px;
box-shadow: 4px 4px 14px rgba(0, 0, 0, 0.15);
transition: max-height 200ms ease-in, box-shadow 200ms ease-in;;
}
.selectbox__list.show {
max-height: 250px;
padding: 5px 8px;
border: 1px solid #c4c4c4;
}
하지만 여기서도 한 가지 이슈를 찾을 수 있었는데, 속도를 충분히 설정해주지 않으면, gif초반에 보이는 언어 선택을 해도 언어가 바뀌지 않는 이슈가 있었다.
이게 속도의 문제라는 것도 아까 새로운 관점을 얻었을 때와 마찬가지로 버그님 강의영상 맨마지막 댓글을 보고 알았다.
혹시나 해서 속도를 200ms -> 500ms
로 변경해준 후 다시 실행시켜 봤다.
전과 같은 이슈 없이 셀렉트 언어가 잘 변경된다. 다른 구역을 누르면 드롭다운이 닫히는 것까지 완벽하다.
그래서 최종 결론은 'CSS에 적어줬던 transition 속성이 JS기능 구현에 영향을 줬다.'인데, 여기에 대해서 정확한 동작원리?는 모르겠다.
명쾌한 설명을 들어보고 싶다.!