>  기사  >  웹 프론트엔드  >  JavaScript 이벤트 학습의 이벤트 스트림, 핸들러 및 객체 요약

JavaScript 이벤트 학습의 이벤트 스트림, 핸들러 및 객체 요약

巴扎黑
巴扎黑원래의
2017-08-16 11:13:121205검색
JS와 HTML 간의 상호 작용은 이벤트를 통해 이루어집니다. 이벤트는 문서나 브라우저 창 내에서 발생하는 특정 상호 작용 순간입니다. 이벤트가 발생할 때 적절한 코드가 실행되도록 리스너(또는 핸들러)를 사용하여 이벤트를 예약할 수 있습니다. 전통적인 소프트웨어 엔지니어링에서 관찰자 패턴으로 알려진 이 패턴은 페이지 동작과 페이지 모양 간의 느슨한 결합을 지원합니다. 이 글에서는 JS 이벤트와 관련된 기본 지식을 소개합니다.
1. 이벤트 흐름
이벤트 흐름은 페이지에서 이벤트가 수신되는 순서를 설명합니다.
이벤트 버블링
이벤트는 처음에 가장 구체적인 요소(문서에서 가장 깊은 중첩 수준을 가진 노드)에 의해 수신된 다음 덜 구체적인 노드(문서)로 위쪽으로 전파됩니다. 다음 HTML 페이지를 예로 들어 보겠습니다. 페이지에서 버튼을 클릭하면 f83a72b083183cd7ada5c1ff71f3c3ad, b85b0a6951c545a2d1f5606946a8c3e1, < 즉, 이벤트 캡처는 이벤트가 문서 객체에서 이벤트의 실제 대상 요소까지 DOM 트리를 따라 아래쪽으로 전파되는 것을 의미합니다.
DOM 이벤트 흐름
"DOM2 수준 이벤트"에서 지정하는 이벤트에는 이벤트 캡처 단계, 대상 단계, 이벤트 버블링 단계의 세 단계가 포함됩니다. 가장 먼저 일어나는 일은 이벤트를 가로챌 수 있는 기회를 제공하는 이벤트 캡처입니다. 그런 다음 실제 대상이 이벤트를 수신합니다. 마지막 단계는 이벤트에 응답할 수 있는 버블링 단계입니다.
이전 버튼 클릭을 예로 들면 DOM 이벤트 흐름에서 캡처 단계 동안 "클릭" 이벤트는 문서에서 시작하여 본문 요소로 전달됩니다. (실제 대상 버튼은 이벤트를 수신하지 않습니다. 캡처 단계 중). 대상 단계에서 버튼 요소는 "클릭" 이벤트를 수신합니다. 마지막으로 버블링 단계에서 이벤트가 문서로 다시 전파됩니다.
2. 이벤트 핸들러
이벤트는 사용자나 브라우저 자체가 수행하는 특정 작업이며, 이벤트에 응답하는 함수를 이벤트 핸들러 또는 이벤트 리스너라고 합니다.
HTML 이벤트 핸들러
여기서 HTML 이벤트 핸들러는 HTML 요소의 속성을 통해 직접 정의된 이벤트 핸들러를 의미합니다. 아래 코드 예제를 참조하세요. 이 경우 이벤트 핸들러는 요소의 속성 값을 캡슐화하는 함수를 생성하며 이 값은 이벤트의 대상 요소와 동일합니다. 이런 방식으로 이벤트 처리기를 지정하면 몇 가지 단점이 있으므로 권장되지 않습니다.
<button onclick="alert(&#39;HaHa~&#39;)">Btn-1</button>
<button onclick="alert(&#39;event.type&#39;)">Btn-2</button>
<button onclick="handler()">Btn-3</button>
<script type="text/javascript">
 function handler() {
  alert("Haha~");
 }
</script>

DOM 레벨 0 이벤트 핸들러
JS를 통해 이벤트 핸들러를 지정하는 전통적인 방법은 이벤트 핸들러 속성에 함수를 할당하는 것입니다. 아래 코드 예제를 참조하세요. 이 방식으로 지정된 이벤트 핸들러는 요소의 범위 내에서 실행되며 이는 현재 요소를 참조합니다. 이러한 방식으로 추가된 이벤트 핸들러는 이벤트 흐름의 버블링 단계에서 처리됩니다. 이벤트를 삭제하려면 onclick 값을 공백으로 설정하면 됩니다.
var btn = document.getElementById("myBtn");
btn.onclick = function() {
 console.log("this.id"); // "myBtn"
};
// 删除事件处理程序
btn.onclick = null;

DOM2 수준 이벤트 핸들러
"DOM2 수준 이벤트"는 이벤트 핸들러를 지정하고 제거하는 두 가지 메서드인 addEventListener()와 RemoveEventListener()를 정의합니다. 이 두 가지 방법은 모든 DOM 노드에 포함되어 있습니다. 두 메소드 모두 처리할 이벤트, 처리 함수, 부울 값이라는 3개의 매개변수를 받습니다. 최종 부울 값은 true인 경우 캡처 단계에서 이벤트 핸들러가 호출되고, 버블링 단계에서 이벤트 핸들러가 호출되는 경우 false임을 의미합니다. DOM0 수준 메서드와 마찬가지로 여기에 추가된 이벤트 핸들러도 연결된 요소의 범위에서 실행됩니다. DOM2 수준 메서드를 사용하여 이벤트 핸들러를 추가하면 여러 이벤트 핸들러를 추가할 수 있다는 장점이 있습니다. 이러한 이벤트 핸들러는 추가된 순서대로 실행됩니다. 다음은 코드 예시입니다.
var btn = document.getElementById("myBtn");
// 添加,触发点击事件时先输出"myBtn"再输出"HaHa~"
btn.addEventListener("click", function() {
 console.log(this.id);
}, false);
btn.addEventListener("click", function() {
 console.log("HaHa~");
}, false);

addEventListener()를 통해 추가된 이벤트는 RemoveEventListener()를 통해서만 제거할 수 있습니다. 삭제 시 전달된 매개변수는 추가 시 사용된 매개변수와 일치해야 합니다. 이는 addEventListener()를 통해 추가된 익명 함수는 삭제할 수 없음을 의미합니다. 추가 시 전달된 익명 함수는 삭제 시 동일한 함수를 작성하더라도 새 익명 함수일 뿐입니다. 아래 코드 예제를 참조하세요.
var btn = document.getElementById("myBtn");
// 无法删除匿名函数
btn.addEventListener("click", function() {
 console.log(this.id);
}, false);
btn.removeEventListener("click", function() {
 console.log(this.id);
}, false);
  
// 正确的添加和删除方式
function handler() {
 console.log(this.id);
}
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false);

대부분의 경우 이벤트 핸들러는 다양한 브라우저와의 호환성을 극대화하기 위해 이벤트 흐름의 버블링 단계에 추가됩니다. 이벤트가 대상에 도달하기 전에 이벤트를 가로채야 하는 경우에만 캡처 단계에 이벤트 핸들러를 추가하는 것이 가장 좋습니다. JS 고급 프로그래밍에서는 특별히 필요하지 않은 경우 이벤트 캡처 단계에서 이벤트 핸들러를 등록하지 않는 것이 좋습니다.
IE 이벤트 핸들러
IE实现了与DOM中类似的两个方法: attachEvent()和deleteEvent()。这两个方法接收两个参数,事件处理程序名称和事件处理程序。注意,第一个参数是事件处理程序名称而不是事件名称,也就是说在注册点击事件的处理程序时应该传入”onclick”而不是”click”,这里跟DOM的方法有些差别。另外,这两个方法注册的事件处理程序是在全局作用域中运行而不是元素作用域,this的值指向window。还有一点需要特别小心,通过attachEvent()方法也可以添加多个事件处理程序,但是它们的执行顺序却不是按照它们被添加的顺序,而是完全相反,跟DOM方法截然不同。突然觉得IE真的特别反人类~~~下面是代码示例:
var btn = document.getElementById("myBtn");
function handler1() { // ... }
function handler2() { // ... }
// 添加,触发点击事件时先执行handler2再执行handler1
btn.attachEvent("onclick", handler1);
btn.attachEvent("onclick", handler2);
// 删除
btn.deleteEvent("onclick", handler1);
btn.deleteEvent("onclick", handler2);

三、事件对象
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息,包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。
DOM中的事件对象
兼容DOM的浏览器会将一个event对象传入事件处理程序中,无论指定事件处理程序时用的是DOM0还是DOM2的方法,都会传入event对象。event对象只有在事件处理程序执行期间才会存在,一旦事件处理程序执行完毕,event对象就会被销毁。下面是代码示例:
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
 console.log(event.type); // "click"
}
btn.addEventListener("click", function(event) {
 console.log(event.type);
}, false);

event对象包含与创建它的特定事件有关的属性和方法,触发的事件类型不一样,可用的属性方法也有所不同。但是所有的事件都会有下列的属性或方法:
bubbles: 布尔值,表示事件是否冒泡
cancelable: 布尔值,表示是否可以取消事件的默认行为
currentTarget: 元素,事件处理程序当前正在处理事件的那个元素
defaultPrevented: 布尔值,表示是否调用过preventDefault()方法
detail: 整数,与事件相关的细节信息
eventPhase: 整数,调用事件处理程序的阶段,1表示捕获阶段,2表示目标阶段,3表示冒泡阶段
preventDefault(): 函数,取消事件的默认行为,cancelable为true时可以调用该方法
stopImmediatePropagation(): 函数,取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用
stopPropagation(): 函数,取消事件的进一步捕获或冒泡,bubbles为true时可以调用这个方法
target: 元素,事件的目标
trusted: 布尔值,为true时表示事件是浏览器生成的,否则表示事件是通过JS创建的
type: 字符串,被触发的事件类型
view: 与事件关联的抽象视图,等同于发生事件的window对象
下面代码示例展示了上述部分属性的用法,也可以帮助我们进一步理解事件流。假设页面中有一个按钮”myBtn”。当点击按钮时,this和currentTarget都等于body元素,因为事件处理程序是注册在body元素上。target的值却等于按钮元素,因为它是click事件的真正目标。由于按钮上没有注册事件处理程序,结果”click”事件冒泡到了document.body那里才得到处理。
document.body.onclick = function(event) {
 console.log(event.currentTarget === document.body); // true
 console.log(this === document.body); // true
 console.log(event.target === document.getElementById("myBtn")); // true
};

再看一个例子,下面代码中,stopPropagation()方法取消了事件的进一步捕获或冒泡。当我点击按钮时,本来应该会因为事件冒泡机制触发按钮和body元素上的点击事件处理程序,输出”From Bth …”和”From Body …”。现在点击事件在按钮元素上触发之后就被阻止继续在DOM层次中的传播,因此body上的事件处理程序不会被触发。
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
 console.log("From Bth ...");
 event.stopPropagation(); // 停止事件传播
};
document.body.onclick = function() {
 console.log("From Body ...");
};

IE中的事件对象
在IE中,使用DOM0的方法添加事件处理程序时,event对象作为window对象的一个属性存在。如果是通过attachEvent()方法添加,则event对象是作为参数传入事件处理函数。下面是代码示例:
var btn = document.getElementById("myBtn");
btn.onclick = function() {
 var event = window.event;
 console.log(event.type); // "click"
};
btn.attachEvent("onclick", function(event) {
 console.log(event.type); // "click"
});

IE的event对象同样也包含与创建它的事件相关的属性和方法,这些属性和方法也会因为事件类型的不同而有所差异。但所有事件对象都会包含下列属性:
cancelBubble: 布尔值,可读可写,默认为false。将其设置为true时取消事件冒泡
returnValue: 布尔值,可读可写,默认为true。将其设置为false时取消事件的默认行为
srcElment: 元素,事件的目标元素,与DOM中的target属性相同
type: 字符串,事件类型
在IE中,事件处理程序的作用域是根据指定它的方式来确定,this的值不一定是指向事件的目标元素。因此,使用srcElement属性更具保险。请看下面代码实例,第一种方式中this的值为目标元素,而第二种方式,前面讲过这种方式的事件处理程序是在全局作用域中执行,因此this的值为window。
var btn = document.getElementById("myBtn");
btn.onclick = function() {
 console.log(window.event.srcElement === this); // true
}
btn.attachEvent("onclick", function(event) {
 console.log(event.srcElement === this); // false
});

위 내용은 JavaScript 이벤트 학습의 이벤트 스트림, 핸들러 및 객체 요약의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.