>  기사  >  웹 프론트엔드  >  js 이벤트 청취 메커니즘(이벤트 캡처)_javascript 기술 요약

js 이벤트 청취 메커니즘(이벤트 캡처)_javascript 기술 요약

WBOY
WBOY원래의
2016-05-16 16:40:101218검색

프론트엔드 개발 과정에서 페이지 요소에 이벤트를 추가하는 문제가 자주 발생합니다. 이벤트를 추가하는 방법에는 여러 가지가 있습니다. 일부는 페이지 구조에 직접 추가되며 일부는 js 이벤트 모니터링 방법을 사용합니다. . 다양한 브라우저로 인해 서버마다 이벤트 버블링 및 이벤트 모니터링 메커니즘이 다릅니다. LE 브라우저에는 이벤트 버블링만 있고 이벤트 모니터링 메커니즘이 없습니다.

1. 페이지 구조에 직접 이벤트 메소드를 작성합니다

function eventfun(){ 
//console.log(this); 
} 
<input type="button" onclick="eventfun()" value="button" />//这里涉及到一个this作用域的问题,eventfun再这里是一个全局函数, 对象是[object Window],this指向的是window.

이 범위의 문제를 해결하려면 전역 함수에 이벤트 변수를 추가하는 방법을 사용하고 이 객체를 페이지 구조 내부의 함수에 매개변수로 전달할 수 있습니다

<input type="button" onclick="eventfun2(this)" value="button2" /> 
function eventfun2(eve){//在这里把事件对象作为参数传递到全局方法里 
eve.name="alex"; 
window.name="robin"; 
console.log(this);//[object Window] 
console.log(eve);// [object HTMLInputElement] 
console.log(this.name);// robin 
console.log(eve.name);// alexvar 
self=eve; 
console.log(this.name);//robin 
console.log(self.name);//alex 
alert(window.name); 
alert(self.name); 
}

2. 이벤트 속성에 값을 할당하는 방법은 이벤트를 바인딩하는 방법이지만, 이 방법의 한계는 이벤트에 하나의 메서드만 바인딩할 수 있다는 것입니다.

에 따라 방법이 사용됩니다.

HTMLElementobject.onclick = fucntion(){//이벤트 속성에 값을 할당하는 이 방법을 사용하면 this의 포인터가 이벤트 객체가 아닌 창 객체를 가리키므로 이 방법은 참조입니다

//js code 
fun1(); 
fun2(); 
fun3(); 
console.log(this);//window.object 
} 
function dosomething(){ 
//js code 
} 
HTMLElementobject.onclick = dosomething;//使用这种为事件对象属性赋值的形式,this指针指向事件执行对象 
console.log(this);//htmlElementObject

3. 이벤트 전파 - 버블링 및 캡처
DOM 이벤트 표준은 크게 다르며 애플리케이션에 상당한 영향을 미칠 수 있는 두 가지 이벤트 흐름을 정의합니다. 두 이벤트 스트림이 캡처되고 버블링됩니다. 많은 웹 기술과 마찬가지로 Netscape와 Microsoft는 표준이 되기 전에 각각 다르게 구현했습니다. Netscape는 캡처 이벤트 스트림을 구현하기로 선택했고 Microsoft는 버블링 이벤트 스트림을 구현했습니다. 다행스럽게도 W3C는 이 두 가지 방법을 조합하여 사용하기로 결정했으며 대부분의 새로운 브라우저는 두 가지 이벤트 스트리밍 방법을 모두 따릅니다.
기본적으로 이벤트는 버블링 이벤트 스트림을 사용하고 캡처 이벤트 스트림을 사용하지 않습니다. 그러나 Firefox 및 Safari에서는 이벤트 등록 시 useCapture 매개변수를 전달하고 이 매개변수를 true로 설정하여 캡처 이벤트 스트림을 사용하도록 명시적으로 지정할 수 있습니다.
버블링 이벤트 스트림
사용자가 고객 이름 노드에서 마우스를 클릭하는 것과 같이 특정 DOM 요소에서 이벤트가 트리거되면 이벤트는 노드가 상속하는 상위 노드를 따르고 해당 노드를 만날 때까지 전체 DOM 노드 계층 구조를 통해 버블링됩니다. 이벤트 유형 핸들러의 노드가 첨부됩니다. 이때 이벤트는 onclick 이벤트입니다. 이벤트 버블링은 버블링 프로세스 중 언제든지 종료될 수 있습니다. W3C 표준을 준수하는 브라우저에서는 이벤트 객체에 대해 stopPropagation() 메서드를 호출할 수 있습니다. Internet Explorer에서는 이벤트 객체의 cancelBubble 속성을 true로 설정할 수 있습니다. . 이벤트 전파를 중지하지 않으면 이벤트는 문서 루트에 도달할 때까지 DOM을 통해 계속 버블링됩니다.
이벤트 스트림 캡처
이벤트 처리는 이벤트를 트리거한 대상 요소에서 시작하는 것이 아니라 DOM 계층 구조의 루트에서 시작됩니다. 이벤트는 대상 요소의 모든 상위 요소에서 순서대로 전달됩니다. 이 과정에서 이벤트는 문서 루트에서 이벤트 대상 요소까지 상속된 각 요소에 의해 캡처됩니다. 이벤트 리스너가 등록 시 useCapture 속성을 true로 설정하면 이 기간 동안 모든 요소로 전달될 수 있습니다. 그렇지 않으면 이벤트가 파생 요소 경로의 다음 요소(대상 요소까지)로 전달됩니다. 이벤트가 대상 요소에 도달한 후 DOM 노드를 통해 버블링됩니다.
최신 이벤트 바인딩 방법
이전 강의에서 설명한 것처럼 기존 이벤트 바인딩을 사용하면 객체의 동일한 이벤트에 대해 여러 이벤트 핸들러를 등록할 수 없는 등 많은 단점이 있습니다. 브라우저와 W3C는 이를 고려하지 않았으므로 최신 브라우저에는 이벤트 바인딩을 위한 자체 방법이 있습니다.
W3C DOM
obj.addEventListener(evtype,fn,useCapture) ——이벤트 처리 기능을 추가하기 위해 W3C에서 제공하는 방법입니다. obj는 이벤트를 추가하는 객체, evtype은 접두사가 없는 이벤트 유형, fn은 이벤트 처리 함수, useCapture가 true이면 이벤트 처리 함수는 캡처 단계에서 실행되고, 그렇지 않으면 버블링 단계에서 실행됩니다. 🎜> obj.removeEventListener(evtype,fn,useCapture)——W3C에서 제공하는 이벤트 핸들러 함수 삭제 방법
Microsoft IE 방식
obj.attachEvent(evtype,fn) ——이벤트 처리 기능을 추가하기 위해 IE에서 제공하는 메서드입니다. obj는 이벤트를 추가하는 객체이고, evtype은 이벤트 유형이며, 접두사가 있고, fn은 이벤트 처리 함수이고, IE는 이벤트 캡처를 지원하지 않습니다
obj.detachEvent(evtype,fn,) ——이벤트 처리 함수를 삭제하기 위해 IE에서 제공하는 메서드에는 on 접두사
가 포함되어 있습니다.

두 가지를 통합하는 방법

function addEvent(obj,evtype,fn,useCapture) { 
if (obj.addEventListener) { 
obj.addEventListener(evtype,fn,useCapture); 
} else { 
obj.attachEvent("on"+evtype,fn);//IE不支持事件捕获 
} else { 
obj["on"+evtype]=fn;//事实上这种情况不会存在 
} 
} 
function delEvent(obj,evtype,fn,useCapture) { 
if (obj.removeEventListener) { 
obj.removeEventListener(evtype,fn,useCapture); 
} else { 
obj.detachEvent("on"+evtype,fn); 
} else { 
obj["on"+evtype]=null; 
} 
}
IE의 Attach 방식에 문제가 있습니다. AttachEvent를 사용할 때 이벤트 처리 함수 내에서 이는 obj가 아닌 window를 가리킵니다. 물론 이에 대한 해결책도 있습니다!

그러나 IE의 attachmentEvent 메소드에는 동일한 함수가 동일한 객체 및 동일한 이벤트에 여러 번 등록될 수 있다는 문제가 있습니다. 해결 방법: IE의 attachmentEvent 메소드를 버리세요! IE의 attachmentEvent 메소드는 캡처를 지원하지 않으며 기존 이벤트 등록과 크게 다르지 않습니다(여러 이벤트 처리 기능을 바인딩할 수 있다는 점 제외). IE의 attachmentEvent 메소드에는 메모리 누수 문제가 있습니다!

addEvent,delEvent 최신 버전

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>js事件监听</title> 
<style> 
table td{font:12px; border-bottom:1px solid #efefef;} 
</style> 
</head> 

<body> 
<div id="outEle" style="padding:10px; border:1px solid #b2b2b2; background:#efefef;"> 
<input type="button" onclick="eventfun()" id="button" value="button" /><br /> 
<input type="button" onclick="eventfun2(this);" id="button2" value="button2" /><br /> 
<input type="button" id="button3" value="button3" /><br /> 
<input type="button" id="button4" value="button4" /><br /> 
<table id="htmlEleTable" width="100%" border="0" style="border:1px solid #b2b2b2; background:#fff;"> 
<tr id="1111"><td>111111111111111111111111111111</td></tr> 
<tr id="22222"><td>222222222222222222222222222222</td></tr> 
<tr id="33333"><td>333333333333333333333333333333</td></tr> 
<tr id="4444"><td>444444444444444444444444444444</td></tr> 
<tr id="55555"><td>555555555555555555555555555555</td></tr> 
</table> 
</div> 
<script language="javascript" type="text/javascript"> 
function eventfun(){//1.直接把js方法写在页面结构上 
console.log(this);//这里涉及到一个this作用域的问题,eventfun再这里是一个全局函数, 对象是window,this指向的是window 
alert(this); 
} 
function eventfun2(eve){//在这里把事件对象作为参数传递到全局方法里 
eve.name="alex";// 
window.name="robin"; 
console.log(this);//[object Window] 
console.log(eve);// [object HTMLInputElement] 
console.log(this.name);// robin 
console.log(eve.name);// alex 
var self=eve; 
console.log(this.name);//robin 
console.log(self.name);//alex 
alert(window.name); 
alert(self.name); 
} 
function eventfun3(){//1.直接把js方法写在页面结构上 
console.log(this);//这里涉及到一个this作用域的问题,eventfun再这里是一个全局函数, 对象是window,this指向的是window 
console.log(this.id); 
alert(this); 
alert(this.id); 
//var outEleObj = EventUtil.$("outEle"); 
//removeEvent(outEleObj,"click",eventfun3); 
} 
/* 
var EventUtil = {}; 
EventUtil.$ = function(id){ 
return document.getElementById(id); 
} 
EventUtil.openmes = eventfun3; 
EventUtil.addEventHandle = function(eventTarget,eventtype,eventHandle){//定义事件监听的对象元素,事件类型,事件函数 
if(eventTarget.attachEvent){ 
eventTarget.attachEvent("on"+eventtype,eventHandle); 
}else if(eventTarget.addEventListener){ 
eventTarget.addEventListener(eventtype,eventHandle,false) 
}else{ 
eventTarget["on" + eventtype] = null; 
} 

}; 
EventUtil.deleEventHandle = function(eventTarget,eventtype,eventHandle){//定义事件监听的对象元素,事件类型,事件函数 
if(eventTarget.detachEvent){ 
alert("on"+eventtype); 
alert("on"+eventHandle); 
eventTarget.detachEvent("on"+eventtype,eventHandle); 
}else if(eventTarget.removeEventListener){ 
eventTarget.removeEventListener(eventtype,eventHandle,false) 
}else{ 
eventTarget["on" + eventtype] = null; 
} 

};*/ 
var EventUtil={ 
$:function(id){ 
return document.getElementById(id); 
}, 
but4fun:function(){ 
console.log(this); 
this.addEventHandle(); 
}, 
eventfun3:function (){ 
console.log(this); 
alert(this); 
delEvent(obj,evtype,fn,useCapture); 
} 
} 
/***使用addEventListener,attachEvent进行dom事件的监听 
function addEvent(obj,evtype,fn,useCapture){ 
if (obj.addEventListener) { 
obj.addEventListener(evtype,fn,useCapture); 
}else if(obj.attachEvent){ 
obj.attachEvent("on"+evtype,function () { 
fn.call(obj); 
}); 
}else { 
obj["on"+evtype]=fn;//事实上这种情况不会存在 
} 
} 
function delEvent(obj,evtype,fn,useCapture) { 
if (obj.removeEventListener) { 
obj.removeEventListener(evtype,fn,useCapture); 
} else if(obj.detachEvent){ 
obj.detachEvent("on"+evtype,fn); 
} else { 
obj["on"+evtype]=null; 
} 
} 



function addEvent(obj,evtype,fn,useCapture) { 
if (obj.addEventListener) {//优先考虑W3C事件注册方案 
obj.addEventListener(evtype,fn,!!useCapture); 
} else {//当不支持addEventListener时(IE),由于IE同时也不支持捕获,所以不如使用传统事件绑定 
if (!fn.__EventID) {fn.__EventID = addEvent.__EventHandlesCounter++;} 
//为每个事件处理函数分配一个唯一的ID 

if (!obj.__EventHandles) {obj.__EventHandles={};} 
//__EventHandles属性用来保存所有事件处理函数的引用 

//按事件类型分类 
if (!obj.__EventHandles[evtype]) {//第一次注册某事件时 
obj.__EventHandles[evtype]={}; 
if (obj["on"+evtype]) {//以前曾用传统方式注册过事件处理函数 
(obj.__EventHandles[evtype][0]=obj["on"+evtype]).__EventID=0;//添加到预留的0位 
//并且给原来的事件处理函数增加一个ID 
} 
obj["on"+evtype]=addEvent.execEventHandles; 
//当事件发生时,execEventHandles遍历表obj.__EventHandles[evtype]并执行其中的函数 
} 
} 
} 

addEvent.__EventHandlesCounter=1;//计数器,0位预留它用 
addEvent.execEventHandles = function (evt) {//遍历所有的事件处理函数并执行 
if (!this.__EventHandles) {return true;} 
evt = evt || window.event; 
var fns = this.__EventHandles[evt.type]; 
for (var i in fns) { 
fns[i].call(this); 
} 
}; 
/* 
function delEvent(obj,evtype,fn,useCapture) { 
if (obj.removeEventListener) {//先使用W3C的方法移除事件处理函数 
obj.removeEventListener(evtype,fn,!!useCapture); 
} else { 
if (obj.__EventHandles) { 
var fns = obj.__EventHandles[evtype]; 
if (fns) {delete fns[fn.__EventID];} 
} 
} 
} 

function fixEvent(evt) {//fixEvent函数不是单独执行的,它必须有一个事件对象参数,而且只有事件发生时它才被执行!最好的方法是把它整合到addEvent函数的execEventHandles里面 
if (!evt.target) { 
evt.target = evt.srcElement; 
evt.preventDefault = fixEvent.preventDefault; 
evt.stopPropagation = fixEvent.stopPropagation; 
if (evt.type == "mouseover") { 
evt.relatedTarget = evt.fromElement; 
} else if (evt.type =="mouseout") { 
evt.relatedTarget = evt.toElement; 
} 
evt.charCode = (evt.type=="keypress")&#63;evt.keyCode:0; 
evt.eventPhase = 2;//IE仅工作在冒泡阶段 
evt.timeStamp = (new Date()).getTime();//仅将其设为当前时间 
} 
return evt; 
} 
fixEvent.preventDefault =function () { 
this.returnValue = false;//这里的this指向了某个事件对象,而不是fixEvent 
}; 
fixEvent.stopPropagation =function () { 
this.cancelBubble = true; 
};*/ 
//console.log(EventUtil.$("button3"));//返回EventUtil函数的对象属性 
//EventUtil.$("button3").onclick= eventfun;//2.使用为对象事件属性赋值的方法来实现事件的监听 
//EventUtil.$("button3").onclick= eventfun2;//为事件属性添加多个方法时,为后者 
//EventUtil.$("button3").onclick= eventfun;//事件捕获是从事件对象逐层外父级检察一直到window对象 
var EventUtil =function(){ 
function getByid(id){ 
return document.getElementById(id); 
}; 
// written by Dean Edwards, 2005 
// with input from Tino Zijdel, Matthias Miller, Diego Perini 

// http://dean.edwards.name/weblog/2005/10/add-event/ 

function addEvent(element, type, handler) { 
if (element.addEventListener) { 
element.addEventListener(type, handler, false); 
} else { 
// assign each event handler a unique ID 
if (!handler.$$guid) handler.$$guid = addEvent.guid++; 
// create a hash table of event types for the element 
if (!element.events) element.events = {}; 
// create a hash table of event handlers for each element/event pair 
var handlers = element.events[type]; 
if (!handlers) { 
handlers = element.events[type] = {}; 
// store the existing event handler (if there is one) 
if (element["on" + type]) { 
handlers[0] = element["on" + type]; 
} 
} 
// store the event handler in the hash table 
handlers[handler.$$guid] = handler; 
// assign a global event handler to do all the work 
element["on" + type] = handleEvent; 
} 
}; 
// a counter used to create unique IDs 
addEvent.guid = 1; 

function removeEvent(element, type, handler) { 
if (element.removeEventListener) { 
element.removeEventListener(type, handler, false); 
} else { 
// delete the event handler from the hash table 
if (element.events && element.events[type]) { 
delete element.events[type][handler.$$guid]; 
} 
} 
}; 

function handleEvent(event) { 
var returnValue = true; 
// grab the event object (IE uses a global event object) 
event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event); 
// get a reference to the hash table of event handlers 
var handlers = this.events[event.type]; 
// execute each event handler 
for (var i in handlers) { 
this.$$handleEvent = handlers[i]; 
if (this.$$handleEvent(event) === false) { 
returnValue = false; 
} 
} 
return returnValue; 
}; 

function fixEvent(event) { 
// add W3C standard event methods 
event.preventDefault = fixEvent.preventDefault; 
event.stopPropagation = fixEvent.stopPropagation; 
return event; 
}; 
fixEvent.preventDefault = function() { 
this.returnValue = false; 
}; 
fixEvent.stopPropagation = function() { 
this.cancelBubble = true; 
}; 
function tableAddEvent(){ 

}; 

return{ 
add:addEvent, 
remove:removeEvent, 
$:getByid 
} 
}(); 

var outEleObj = EventUtil.$("outEle"); 
//addEvent.apply(EventUtil,[outEleObj,"click",eventfun3]); 
//EventUtil.add(outEleObj,"click",eventfun3); 
var inputObj = EventUtil.$("button4"); 
var tableEle = EventUtil.$("htmlEleTable"); 
var tabTrEle = tableEle.getElementsByTagName("tr"); 
EventUtil.add(tableEle,"click",eventfun3); 
for (i=0; i<tabTrEle.length; i++){ 
EventUtil.add(tabTrEle[i],"click",eventfun3); 
} 
EventUtil.remove(tableEle,"click",eventfun3);//事件冒删除方法 
EventUtil.add(tableEle,"click",eventfun3);//事件冒泡添加方法 
//EventUtil.add(inputObj,"click",eventfun3); 
//EventUtil.remove(outEleObj,"click",eventfun3); 
//console.log(addEvent); 
//addEvent(inputObj,"click",eventfun3,true); 
//delEvent(outEleObj,"click",eventfun3,false); 
</script> 
</body> 
</html>

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