개인적인 생각이지만, "나 자바스크립트로 웹페이지 만들수있어요"라고 말할때 가장 티낼수있는 부분이 이벤트 파트라고 생각한다.
웹사이트를 구현했을 때 가장 임펙트있는 부분은 이벤트를 통한 기능일테니까 말이다.
나 또한 처음 이벤트부분을 공부할때 그냥 addEventListener로 이벤트 리스닝하고, 함수 트리거 하면 끝, 이라 생각했고
이렇게만 하면 대충 클릭할때 이벤트 발생 ~, 양식 제출도 할 수 있고~ ...
지금 다시 복습하면서 느낀점은 여기가 절대 단순한 파트가 아니고 여러 원리를 이해해야 진정으로 이벤트를 다룰수 있다고 생각하게 되었다.
(예를들어, form으로 양식제출시 event.preventDefault() 사용하긴 했는데,, 그냥 백엔드로 전송되는거 막아준다, 라고만 알고 사용했었다..)
이번 글에서 알아볼 것
- 이벤트(객체)란? 이벤트 리스닝이란?
- event.preventDefault();는 왜 사용하고, 정확히 무엇을 수행할까?
- 버블링(Bubbling) & 캡쳐링(Capturing)
- 드래그 & 드롭
- *참고: 이벤트 헨들러 함수와 this
1. 이벤트(객체)란? 이벤트 리스닝이란?
- 우리가 말하는 이벤트를 사용한다란,,즉 자바스크립트에서 이벤트란 어떠한 행동(ex, 클릭)을 했을 때 어떠한 로직이 실행되는 것을 말한다
- 이러한 이벤트에는 이벤트 객체가 존재하는데, 이를 자세히 살펴보자
const buttonClickHandler = (event) => {
console.log(event);
};
button.addEventListener("click", buttonClickHandler);
- 이벤트 객체를 console.log로 찍어보니 어마어마한 양의 데이터가 들어가있는 것을 확일할 수 있었다
- 여기서 중요한 프로퍼티들이 있겠지만, 내가 집중하고 싶은 것은 target 프로퍼티다
- target 프로퍼티는 어떤 요소가 이벤트의 원인이 되는지 설명하는 프로퍼티이다
- 즉, target 프로퍼티는 우리가 클릭한 직접 요소에 대한 직접적인 엑서스를 제공해준다
- input 태그 → event.target.value / button 태그 → event.target.disable …
이벤트에 대해 알아봤으니, 이제 이 이벤트를 어떻게 사용하는지인데,,,이는 이벤트 리스닝을 통해 수행된다
- 이벤트 리스닝은 앞에서 말했듯 어떤 이벤트인지 듣고, 그에대한 동작을 트리거하는 것이다
- 이러한 이벤트 리스닝 방법에는 3가지 방법이 존재한다
- 쿼리 또는 탐색을 통해 요소에 접근한 후 addEventListener을 이용 (여태까지 해왔던 방법이고, 가장 권장되는 방법이다.)
- HTML 태그의 on~속성 이용
- <button onclick="alert('Hello!')">Click me</button>
- 사용하지말자...너무 오래된 방식이다
- 사용안하는 이유는 여러가지지만, 가장 큰 이유는 html 문서에 스크립트 코드를 넣는 행위는 최대한 자제하는 것이 권장된다
- 쿼리 또는 탐색을 통해 요소에 접근한 후 on~속성 이용
- 2번이랑 비슷하지만, 이는 따로 js파일에 정의해서 사용한다는점이 다르다
- 하지만, 하나의 요소에 하나의 헨들러만 사용가능하다는 단점 존재한다
- 따라서, 이 방법도 권장되지 않는다
const button = document.querySelector("button");
const buttonClickHandler = () => {
alert("Hello!");
};
button.onclick = buttonClickHandler;
- 결론
- 그냥 해오던대로 1번 사용하자
만약, 리스닝한 이벤트를 삭제할려면 어떻게 해야 할까?
- removeEventListener 사용
setTimeout(() => {
button.removeEventListener("click", buttonClickHandler);
}, 2000);
- removeEventListener 주의점
- removeEventListener는 리스닝 설정을 특정해서 지우는 것이기 떄문에, buttonClickHandler자리에 다른 주소의 함수 객체를 사용하면 작동 x (ex, 내용같은 익명함수 => 동작 안함)
button.addEventListener("click", () => {
console.log("asdf");
});
button.removeEventListener("click", () => {
console.log("asdf");
});
- bind(this) 붙이면 새로운 함수 객체가 생성되므로 동작 안함
button.addEventListener("click", buttonClickHandler.bind(this));
button.removeEventListener("click", buttonClickHandler.bind(this));
2. event.preventDefault()
프론트에서 form을 통해 양식을 제출할 때 event.preventDefault()를 사용했다.
- 왜 사용했을까?
- form의 기본 동작인 양식 제출시 자동으로 서버로 데이터를 보내는 행위를 막아주었기 때문이다.
- 결국, event.preventDefault()는 단순히 서버로 데이터 전달하는 것을 막는 것이 아니라, 해당 이벤트의 기본 동작을 막아준다
3. 버블링(Bubbling) & 캡쳐링(Capturing)
<section>
<div>
<button></button>
</div>
</section>
- 브라우저는 이벤트가 트리거되면(ex, 버튼 클릭..) 두 단계로 실행되어, 해당 이벤트에 대한 리스너를 확인한다
- 캡쳐링(Capturing)
- 외부(section)부터 내부(button)으로 이동하면서 이벤트 함수가 존재하는지 확인하고 있다면 먼저 실행시킨다
- 버블링(Bubbling)
- 내부(button)부터 외부(section)으로 이동하면서 이벤트 함수가 존재하는지 확인하고 있다면 먼저 실행시킨다
- 캡쳐링(Capturing)
- 특별히 설정하지 않으면 브라우저는 버블링으로 수행한다
*참고
- event.stopPropagtion()
- button과 그것을 감싸는 div에 모두 click 이벤트가 있을때 button 헨들러 함수에 event.stopPropagtion()을 넣어주면 버튼을 눌렀을 때 div click이벤트는 실행되지 않는다
4. 드래그 & 드롭
웹페이지를 보다보면 어떤 요소를 드래그해서 원하는 위치에 드롭할 수 있는 기능이 존재하는 것을 볼수있다.
이러한 기능을 구현하기 위해서 드래그 & 드롭에 대해 알아보자
- 드래그 & 드롭 순서
- 드래그 시킬 요소의 속성 or 프로퍼티가 draggable 상태여야함
- 드래그 가능 요소에서 dragstart 이벤트를 수신함
- 자바스크립트에게 어느 요소에 드롭될것이지 알려줌
- dragenter & dragover 이벤트 이용
- dragenter 이벤트는 대상 요소로 무언가를 드래그한 다음 중지되는 순간에 발생하고, dragover 이벤트는 드래그하는 동안 드롭할 때까지 발생한다.
- dragenter & dragover 이벤트 이용
- 이벤트 헨들러 함수에 event.preventDefault() 호출
- 왜냐하면, 기본값은 드롭 작업을 취소하는 것이기 때문
- (옵션) dragleave 이벤트 수신가능
- 스타일을 업데이트해줌
- (옵션) dragend 이벤트 수신가능
- 스타일을 업데이트해줌(단, 요소가 원하지않은, 유요하지않은 곳에 드롭되어도 늘 작동한다)
- 코드로 살펴보자
<!-- html -->
<li ~ .. draggable="true” …></li>
// 드래그
connectDrag() {
document.getElementById(this.id).addEventListener("dragstart", (event) => {
event.dataTransfer.setData("text/plain", this.id);
event.dataTransfer.effectAllowed = "move"
});
}
// 드롭
connectDroppable() {
const list = document.querySelector(`#${this.type}-projects ul`);
list.addEventListener("dragenter", (event) => {
if (event.dataTransfer.types[0] === "text/plain") {
list.parentElement.classList.add("droppable");
event.preventDefault();
}
});
list.addEventListener("dragover", (event) => {
if (event.dataTransfer.types[0] === "text/plain") {
event.preventDefault();
}
});
list.addEventListener("dragleave", (event) => {
if (event.relatedTarget.closest(`#${this.type}-projects ul`) !== list) {
list.parentElement.classList.remove("droppable");
}
});
}
// 적용
list.addEventListener("drop", (event) => {
const prjId = event.dataTransfer.getData("text/plain");
if (
this.projects.find((p) => {
return p.id === prjId;
})
) {
return;
}
document.getElementById(prjId).querySelector("button:last-of-type").click();
list.parentElement.classList.remove("droppable");
// event.preventDefault();
});
*참고: 이벤트 헨들러 함수와 this
저번글에서 살펴본 this의 개념은
- 함수 내에서, 즉 해당 함수가 객체의 일부인지와 상관없이 this 키워드는 해당 함수를 호출한 모든 항목을 참조한다
그렇다면 이벤트 헨들러 함수에서 this는 뭘 가르킬까?
<form action="">
<label for="title">Title</label>
<input type="text" id="title" />
<button type="submit">Submit</button>
</form>
<ul>
<li>Item1</li>
<li>Item1</li>
<li>Item1</li>
<li>Item1</li>
<li>Item1</li>
</ul>
const form = document.querySelector("form");
list.addEventListener("click", (event) => {
event.target.classList.toggle("highlight");
form.submit();
});
- 위의 코드는 프로그래밍적으로 DOM 요소 트리거하여 li 요소를 클릭했을때 양식을 제출하는 코드이다.
- 만약 this가 이벤트 헨들러함수에 존재하면, this는 무엇을 가르킬까?
- this는 li요소를 가르킨다(화살표 함수는 제외..)
사실 이벤트에 대해서 살펴볼 개념이 아직 하나 남았는데,
바로 이벤트 위임이라는 개념이다.
하지만 내가 아직 정확히 이해를 하지 못하여 정리하지 못하였다.
나중에 추가해야겠다.
'OLD > Javascript' 카테고리의 다른 글
[Javascript] 자바스크립트 Number & String (부동 소수점, BigInt, 태그된 템플릿) (0) | 2023.02.24 |
---|---|
[Javascript] 자바스크립트 고급 함수 (순수 함수 & 부수 효과, 팩토리 함수, 클로저) (0) | 2023.02.23 |
[Javscript] 자바스크립트 this (0) | 2023.02.21 |
[Javascript] 자바스크립트에서의 객체(프로퍼티, 객체 복사, 대괄호를 통한 동적 접근..) (0) | 2023.02.20 |
[Javascript] 자바스크립트 배열_03 (reduce(), 스프레드 연산자, 배열 구조 분해) (0) | 2023.02.20 |