3. 이벤트 흐름


* 이벤트 흐름과 이벤트 리스너

발생한 이벤트는 window 객체로부터 DOM 트리를 타고 중간 DOM 객체들을 거쳐 타겟 객체로 흘러가고, 다시 반대 방향으로 이동하여 window 객체에 도달한 후 없어진다. 이 과정을 이벤트 흐름이라고 부른다.

이벤트가 흘러가는 경로에 있는 모든 DOM 객체들에게 순서대로 이벤트 객체가 전달되며, DOM 객체에 이벤트 리스너가 작성되어 있으면 모두 실행된다. W3C에서는 이벤트 흐름을 다음 2개의 과정으로 나누어 설명한다.


- 캡쳐 단계(capturing phase)

window에서 타겟 객체까지 이벤트 객체가 전파되는 과정이다. window와 중간에 있는 모든 DOM 객체들을 거쳐 타겟 객체에 이벤트 객체가 전달된다.

캡쳐 단계에서 실행되도록 작성된 리스너를 캡쳐 리스너라고 부른다.


- 버블 단계(bubbling phase)

이제 다시 타겟 객체에서 거꾸로 window까지 이벤트 객체가 전파되는 과정이다.

버블 단계에서 실행되도록 작성된 이벤트 리스너를 버블 리스너라고 부른다.


* 이벤트 흐름 사례















* 캡쳐 리스너와 버블 리스너

하나의 DOM 객체는 캡쳐 리스너와 버블 리스너를 모두 가질 수 있다. 그러므로 이벤트 리스너를 등록할 때 캡쳐 리스너인지 버블 리스너인지 분명히 지정하여야 한다.

addEventListener()의 경우, 3번째 매개 변수가 true이면 캡쳐 리스너로, false이면 버블 리스너로 등록한다.


ex)

var b = document.getElementById("button");

b.addEventListener("click",capFunc,true); // 캡쳐 단계에서 capFunc() 실행

b.addEventListener("click",bubbleFunc,true); // 버블 단계에서 bubbleFunc() 실행


* 이벤트 객체의 멤버 중 이벤트의 흐름과 관련된 멤버

cancelable // 프로퍼티 // 디폴트 행동 취소 가능한 이벤트 여부. true/false 값

stopPropagation() // 메소드 // 객체에 등록된 리스너들 모두 실행 후 이벤트 흐름 중단

stopImmediatePropagetion() // 메소드 // 현재 리스너만 실행하고 이벤트 흐름 즉각 중단


* 이벤트 흐름을 중단시킬 수 있는가? YES

이벤트가 흘러가는 도중 임의의 리스너에서 다음과 같이 이벤트 객체의 stopPropagation() 메소드를 호출하면 이벤트는 더 이상 전파되지 않고 사라진다.


event.stopPropagation(); // event가 이벤트 객체일 때


* 캡쳐와 버블 리스너중 어떤 것이 좋을까?

- DOM 객체는 캡쳐 리스너와 버블 리스너를 모두 가질 수 있지만, 대부분 개발자들은 한 개의 리스너만 작성한다. 익스플로러에 익숙해서 그런지 현재 많은 웹 개발자들이 버블 리스너를 선호한다.


* 이벤트 흐름은 항상 일어나는가? NO

- 모든 이벤트에 대해 캡쳐 단계는 항상 진행되지만, 이벤트에 따라 버블 단꼐는 생략되기도 한다. 버블 단계가 생략되는 대표적인 이벤트가 blur와 focus이다.



예제 9-8. 이벤트 흐름

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>이벤트 흐름</title></head>
<body>
<p style="color:blue">이것은
    <span style="color:red" id="span">문장입니다.
    </span>
</p>
<form>
    <input type="text" name="s">
    <input type="button" value="테스트" id="button">
    <hr>
</form>
<div id="div" style="color:green"></div>
<script>
var div = document.getElementById("div"); // 이벤트 메시지 출력 공간
var button = document.getElementById("button");
 
// body 객체에 캡쳐 리스너 등록
document.body.addEventListener("click", capture, true); // 켭쳐 단계(1)
 
// 타겟 객체에 버블 리스너 등록
button.addEventListener("click", bubble, false); // 버블 단계(2)
 
// body 객체에 버블 리스너 등록
document.body.addEventListener("click", bubble, false); // 버블 단계(3)
 
function capture(e) { // e는 이벤트 객체
    var obj = e.currentTarget; // 현재 이벤트를 받은  DOM 객체
    var tagName = obj.tagName; // 태그 이름
    div.innerHTML += "<br>capture 단계 : " + tagName + " 태그 " + e.type + "이벤트";
}
 
function bubble(e) { // e는 이벤트 객체
    var obj = e.currentTarget; // 현재 이벤트를 받은  DOM 객체
    var tagName = obj.tagName; // 태그 이름
    div.innerHTML += "<br>bubble 단계 : " + tagName + " 태그 " + e.type + "이벤트";
}
</script>
</body>
</html>
 
cs



Posted by 너래쟁이
: