코드스쿼드 코코아과정 3주차 TIL - Part2
지금 구현된 코드가 아래 조건을 만족하는지 체크해보고 코드를 개선해보자.
지금 구현한 기능 이외에 추가적인 기능을 스스로 기획해서 한 가지 추가한다.
Ex. 수정기능, 날짜별 TODO보기 기능 (날짜별로 한일/할일 레이어가 화면에 여러개 노출), 등.
지금까지 배운 내용을 짧은 블로그 또는 마크다운으로 정리하고 공유한다.
📚 그 과정에서 새롭게 알게 된 것들:
버튼에 addEventListener
로 콜백함수를 설정해주는 과정에서 문제가 생겼다.
아무리 button
에 클릭을해도 콜백함수가 실행이 되지를 않았다.
addEvent() {
const button = document.querySelector(".button");
const inputText = document.querySelector(".task_text");
button.addEventListener('click', (inputText) => { 📌📌📌
if (inputText.value === "") {
alert("입력칸이 비었습니다. 할 일을 입력하세요.");
} else {
const currentValue = document.querySelector(".task_text").value;
this.view.makeNewLi(currentValue);
this.model.saveNewData();
inputText.value = "";
}
});
}
계획대로라면 아무런 text가 입력되지 않았을 때 alert창으로 메세지를 띄워줘야하는데, (야속하게도)빈 객체가 잘만 추가 되었다.
debugger로 inputText
에 담긴 요소도 확인해보고 console.log도 실행해보았지만, 초기에 문제원인이라고 예상했던 inputText
는 정상적으로 요소를 담고 있었다.
한참을 씨름한 결과, addEventListener
의 두번째 인자인 화살표함수의 parameter를 ()
로 비워두자 실행이 되었다!
클로저(Closure)가 클로저변수를 저장해주기 때문이다.
JavaScript의 클로저(Closure)란, 함수가 선언될 당시 (혹은 생성될 당시) 주변 환경(Lexical Environment)와 함께 갇히는 것을 의미한다.
클로저는 함수가 선언되는 주변 환경과 관련하여 생성되는 개념으로, 실행되는 장소나 시점은 관계가 없다!
그래서 parameter로 전달하지 않아도 콜백함수 내에서 바로 inputText
로 가져와서 사용하면 된다.
이제button.addEventListener()
함수는 생성될 당시 주변 환경(inputText
를 포함해서)을 지속적으로 기억할 수 있기 때문이다.
이 부분을 수정해 밑의 코드로 다시 실행하니 원하는 결과를 얻을 수 있었다❗️
addEvent() {
const button = document.querySelector(".button");
const inputText = document.querySelector(".task_text");
button.addEventListener('click', () => { 📌📌📌 //(inputText) -> ()
if (inputText.value === "") {
alert("입력칸이 비었습니다. 할 일을 입력하세요.");
} else {
const currentValue = document.querySelector(".task_text").value;
this.view.makeNewLi(currentValue);
this.model.saveNewData();
inputText.value = "";
}
});
}
_(underbar)
를 더 많이 쓰는 편.<li>
)가 현업에서 상당히 많이 쓰인다.(예상보다 훨씬 더 자주!)addEventListener()
에서 콜백 함수명을 지을때는 clickEventHandler
라고 짓는 걸 추천.<웹to-do 과제 2차 리팩토링>
<공부가 필요한 주제들>
이벤트 위임(Delegation):
상위 요소에서 하위 요소의 이벤트들을 제어하는 방식으로, 요소마다 이벤트 핸들러를 할당하지 않고, 요소의 공통 조상에 이벤트를 할당해 여러 요소를 한꺼번에 다룬다. 비슷한 방식으로 여러 요소를 다뤄야 할 때 사용된다.
어떤 프레임워크를 쓰느냐와는 관계없이 기본적인 브라우저의 이벤트 감지 방식!
공통 조상에 할당한 핸들러에서event.target
을 이용하면 실제로 정확히 어디에서 이벤트가 발생했는지 알 수 있다.
이벤트 버블링(Event Bubbling):
이벤트 발생 시 해당 이벤트가 하위 요소 ➡️ 최상위 요소까지 전파되는 과정.
하위 요소 중 하나를 클릭하면 순차적으로 최상위에 있는 화면 요소까지 이벤트들이 실행된다.
ex. li태그로 추가 되어 있는 모든 input박스에 이벤트 리스너를 각각 추가하는 대신 상위 요소인 ul태그에 이벤트 리스너를 달면 하위에서 발생한 클릭 이벤트를 감지한다.<주의>
각 태그마다 이벤트가 등록되어 있을 때만 상위요소로 전달이 일어남.
이벤트 캡쳐(Event Capture):
이벤트 발생 시 최상위 요소 ➡️ 해당 하위 요소를 찾아 내려가면서 이벤트가 전파되는 과정.
이벤트 버블링과는 반대 방향으로 진행된다.
addEventListener()
를 사용하면서 옵션 객체에capture:true
를 설정해주면, 해당 이벤트를 감지하게 위해 이벤트 버블링과는 반대 방향으로 탐색한다.//ex. divs.forEach(function(div) { div.addEventListener('click', logEvent, { capture: true 📌📌📌 }); });
<주의>
마찬가지로 각 태그마다 이벤트가 등록되어 있어야 한다.
event.stopPropagation():
이벤트가 전파되는 것을 막고싶다면stopPropagation()
을 사용하기.
이벤트 버블링의 경우에는 클릭한 요소의 이벤트만 발생시키고 상위 요소로 이벤트를 전달하는 것을 방해한다. 그리고 이벤트 캡쳐의 경우에는 클릭한 요소의 최상위 요소의 이벤트만 동작시킨다.
(이 외에도preventDefault()
와return false
를 사용할 수도 있다.)
https://joshua1988.github.io/web-development/javascript/event-propagation-delegation/
https://ko.javascript.info/event-delegation
https://programmingsummaries.tistory.com/313
https://namu.wiki/w/%EC%96%B8%EB%8D%94%EC%8A%A4%EC%BD%94%EC%96%B4