Event | 모든 이벤트 종류
DOM Node & EventTarget
The DOM represents a document with a logical tree. Each branch of the tree ends in a node, and each node contains objects. The root of the hierarchy is EventTarget, that is inherited by Node, and other DOM nodes inherit from it.
DOM tree는 DOM을 데이터 구조인 tree로 표현한 것이다. tree의 각 branch는 모두 node로 끝나는데, node는 "event target" 이라는 상위 객체를 상속한다.
EventTarget은 "Event"를 받을 수 있는 모든 객체를 일컫는 추상적인 객체로, add/remove/dispatch EventListener라는 메서드가 구현되어있는데, 이 덕분에 event target을 상속하는 모든 객체는 EventListener를 이용할 수 있다. 즉, 모든 DOM node에 이벤트 리스너를 등록해서, 특정 이벤트가 발생했을 때 어떤 처리를 할 것인지를 코드로 작성할 수 있다.
Adding Events
- ❌ HTML inline-events | html 태그 내부에 이벤트와 관련된 속성과 값을 직접 지정한다.
- html 파일 안에서 js 코드를 작성하기 때문에 좋지 않다.
- <h1 onclick = "console.log('you clicked me')">Look at my pokemon!</h1>
- JS events | js 파일에서 on 이벤트가 발생했을 때 처리할 코드를 작성한다.
- console.dir(element) 에서 다양한 on 이벤트 목록을 확인해 볼 수 있다.
- element.onclick = function() { }
- 이벤트 속성의 값을 지정하는 것이기 때문에, 함수 표현식을 할당해 주어야 한다.
- 같은 이벤트 속성에 다른 함수를 등록하면 값이 덮어쓰기 되기 때문에, 하나의 이벤트에 하나의 함수만을 등록할 수 있다.
- ✅ JS addEventListener( "eventType", "functionExpr", { option: value }? )
this keyword in Events
함수 내부에서 사용되는 this 키워드가 있을 때, this가 가리키는 것은 해당 함수가 실행되는 컨텍스트, 즉 함수를 어떻게 호출하고 있느냐에 따라서 달라진다. 아래의 첫번째 예시에서 함수를 호출하고 있는 것은 btn이므로 this가 가리키고 있는 것은 btn이다.
그러나 화살표 함수 내부에서 사용되는 this 키워드는 다르게 동작한다. 이 때 this는 함수의 바로 상위 scope의 this가 가리키는 것과 바인딩 되고, 두번째 예제에서 화살표 함수의 상위 scope는 global object이므로 this는 바로 window를 가리키게 된다.
// 1. annoymous funtionn
btn.addEventListener('click', function () {
console.log(this); // btn
});
// 2. arrow function
btn.addEventListener('click', () => {
console.log(this); // window
});
this를 이용하면 코드의 재사용성을 크게 높일 수 있다.
function colorize() {
this.backgroundColor = `rgb(${getRandomColor())}`;
this.color = `rgb(${getRandomColor())}`;
}
h1.addEventListener("click", colorize);
p.addEventListener("click", colorize);
button.addEventListener("click", colorize);
Bubbling & Delegation
bubbling
웹 페이지를 만들 때 딱 하나의 요소에만 이벤트를 등록하고, 처리하는 것은 아니다. 예를 들어 부모 컨테이너가 있고, 그 안에 자식 요소인 버튼이 있다고 해보자. 컨테이너에도 이벤트를 등록하고, 버튼에도 이벤트를 등록했다. 컨테이너를 클릭하면 어떤 일이 발생할까? 당연히, 컨테이너의 클릭 이벤트에 등록한 콜백 함수가 호출될 것이다.버튼을 클릭했을 때에는? 당연히 버튼에 등록된 콜백 함수가 호출된다. 그런데 이 때에는, 컨테이너에 등록된 콜백함수도 호출된다. 왜 이런 일이 일어나는 걸까?
버튼이 컨테이너의 자식 요소이기 때문이다. 버튼을 클릭하는 것을, 버튼을 포함하고 있는 컨테이너의 일부를 클릭했다는 의미로 받아들인다. 이렇게 자식요소에서 이벤트가 발생했을 때, 그 부모에 등록된 이벤트도 실행하는 것을 event bubbling 이라고 한다. 만약 자식 요소에 등록된 콜백 함수만 호출하고 싶을 때에는 어떻게 해야할까?
- ❌ event.stopPropagation() | 자식 요소에 해당 API를 실행하면, 이벤트 버블링이 일어나지 않는다.
- 자식 요소에 이벤트가 발생했을 때, 모든 부모 요소에 등록되어있는 이벤트가 무용지물이 된다.
- ✅ event delegation
delegation
자식 요소에 이벤트를 "직접" 등록하면, 나중에 부모 요소에 이벤트가 등록되었을 때 bubbling에 의해 원치 않는 콜백 함수가 호출될 수 있다. 또는 어떤 요소가 동적으로 생성된다면(ex. 사용자에 의해 li 추가), 코드를 작성하는 시점에서는 요소가 존재하지 않기 때문에 그 요소에 직접 이벤트를 등록할 수 없다.
이럴 때 자식 요소에는 이벤트를 등록하지 않고, 부모 요소에만 이벤트를 등록해서 bubbling이 일어나지 않도록, 또는 미리코드를 작성하는 시점에 존재하고 있는 부모 요소에 이벤트를 등록하는 코드를 작성할 수 있다. 자식 요소의 이벤트를 부모 요소에게 위임(deleagtion)하기 때문에, 이를 event delegation 이라고 한다.
예를 들어 부모 컨테이너에 각각 다른 일을 하는 자식 요소로 버튼 5개가 있다고 해보자. event delegation을 이용한다는 것은, 5개의 자식 버튼에 각각 콜백 함수를 등록하는 것이 아니라, 부모 컨테이너에 한번만 이벤트를 등록해서 원하는 일을 수행하는 것을 말한다. 이것을 가능하게 도와주는 것은, 이벤트가 발생하면 생성되는 event object의 몇몇 property이다.
- event.target | 마우스 이벤트가 발생한 요소를 반환
- console.dir(event.target) | 해당 객체에서 이용가능한 method와 property를 모두 확인할 수 있다.
- event.currentTarget | read-only, 이벤트가 등록되어 있는 요소를 반환
- 아래 예제 코드에서는 container에 이벤트가 등록되어있으므로, 컨테이너를 클릭하든, 컨테이너의 자식 요소를 클릭하든 currentTarget은 모두 container를 반환한다.
const container = document.querySelector('ul'); // ul > li...
container.addEventListener("click", function(event) {
event.target.nodeName === "LI" && event.target.remove();
};
});
'Study > DOM' 카테고리의 다른 글
Intersection Observer (0) | 2022.07.06 |
---|---|
Window & Document object (0) | 2022.04.18 |
Event types & object (0) | 2022.04.08 |
Select & Manipulate (0) | 2022.04.07 |
What is DOM? (0) | 2022.04.07 |