首頁 web前端 js教程 js事件監聽機制(事件擷取)總結_javascript技巧

js事件監聽機制(事件擷取)總結_javascript技巧

May 16, 2016 pm 04:40 PM
事件捕獲 事件監聽

在前端開發過程中我們經常會遇到給頁面元素添加事件的問題,添加事件的js方法也很多,有直接加到頁面結構上的,有使用一些js事件監聽的方法,由於各個瀏覽器對事件冒泡事件監聽的機制不同,le瀏覽器只有事件冒泡,沒有事件監聽的機制,對於事件監聽的兼容性問題是最大的難題:

1.直接把事件的方法寫在頁面結構上

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

要解決this作用域的問題,可以使用為全域函數新增event變數的方法,在頁面結構上將this物件作為參數傳遞到函數內部使用

<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的指針會指向window對象,而不是被事件對象,所以這種方法是引用

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

3.事件傳播-冒泡與捕獲
DOM事件標準定義了兩種事件流,這兩個事件流有著顯著的差異並且可能對你的應用程式有相當大的影響。這兩種事件流分別是捕獲和冒泡。和許多Web技術 手術一樣,在它們成為標準之前,Netscape和微軟各自不同地實作了它們。 Netscape選擇實現了擷取事件流,微軟實作了冒泡事件流。幸運的 是,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是事件類型,不帶on前綴,fn是事件處理函數,如果useCapture是true,則事件處理函數在捕獲階段被執行,否則 在冒泡階段執行
obj.removeEventListener(evtype,fn,useCapture)-W3C提供的刪除事件處理函數的方法
微軟IE方法
obj.attachEvent(evtype,fn)-IE提供的新增事件處理函數的方法。 obj是要加入事件的對象,evtype是事件類型,帶on前綴,fn是事件處理函數,IE不支援事件擷取
obj.detachEvent(evtype,fn,)-IE提供的刪除事件處理函數的方法,evtype包含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時在事件處理函數內部,this指向了window,而不是obj!當然,這個是有解決方案的!

但IE的attachEvent方法有另一個問題,同一個函數可以被註冊到同一個物件同一個事件上多次,解決方法:拋棄IE的 attachEvent方法吧! IE下的attachEvent方法不支援捕獲,和傳統事件註冊沒有多大區別(除了能綁定多個事件處理函數),並且IE的 attachEvent方法存在內存洩漏問題!
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

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1663
14
CakePHP 教程
1419
52
Laravel 教程
1313
25
PHP教程
1264
29
C# 教程
1237
24
js中點擊事件為什麼不能重複執行 js中點擊事件為什麼不能重複執行 May 07, 2024 pm 06:36 PM

JavaScript 中的點擊事件無法重複執行,原因在於事件冒泡機制。為了解決此問題,可以採取以下措施:使用事件擷取:指定事件偵聽器在事件冒泡之前觸發。移交事件:使用 event.stopPropagation() 阻止事件冒泡。使用計時器:在一段時間後再次觸發事件偵聽器。

事件捕獲有什麼作用 事件捕獲有什麼作用 Nov 01, 2023 pm 01:16 PM

事件擷取的作用包括方便取得目標元素和上下文資訊、有效防止事件冒泡、自訂事件處理邏輯和提高頁面回應速度等。詳細介紹:1、方便獲取目標元素和上下文信息,在事件捕獲階段,當一個事件發生時,瀏覽器會從最外層元素開始逐層向下查找與該事件相關聯的元素,直到找到目標元素為止;2、有效防止事件冒泡,在事件模型中,一個事件發生時,會從最外層元素開始逐層向下傳遞,這個過程被稱為事件冒泡等等。

前端開發中的事件冒泡和事件捕獲的實際應用案例 前端開發中的事件冒泡和事件捕獲的實際應用案例 Jan 13, 2024 pm 01:06 PM

事件冒泡與事件擷取在前端開發中的應用案例事件冒泡與事件擷取是前端開發中常用到的兩種事件傳遞機制。透過了解和應用這兩種機制,我們能夠更靈活地處理頁面中的互動行為,提高使用者體驗。本文將介紹事件冒泡和事件捕獲的概念,並結合具體的程式碼範例,展示它們在前端開發中的應用案例。一、事件冒泡和事件捕獲的概念事件冒泡(EventBubbling)事件冒泡是指在觸發一個元

什麼是事件冒泡事件捕獲 什麼是事件冒泡事件捕獲 Nov 21, 2023 pm 02:10 PM

事件冒泡和事件捕獲是指在HTML DOM中處理事件時,事件傳播的兩種不同方式。詳細介紹:1.事件冒泡是指當一個元素觸發了某個事件,該事件將從最內層的元素開始傳播到最外層的元素。也就是說,事件首先在觸發元素上觸發,然後逐級向上冒泡,直到達到根元素;2、事件捕獲則是相反的過程,事件從根元素開始,逐級向下捕獲,直到達到觸發事件的元素。

利用JavaScript和騰訊地圖實現地圖事件監聽功能 利用JavaScript和騰訊地圖實現地圖事件監聽功能 Nov 21, 2023 pm 04:10 PM

很抱歉,但我無法為您提供完整的程式碼範例。不過我可以為您提供一個基本的思路和範例程式碼段,以供參考。以下是一個簡單的JavaScript和騰訊地圖結合的範例,用於實現地圖事件監聽的功能://引入騰訊地圖的APIconstscript=document.createElement('script');script.src='https://map.

有效阻止事件冒泡的方法 有效阻止事件冒泡的方法 Feb 19, 2024 pm 08:25 PM

如何有效地阻止事件冒泡,需要具體程式碼範例事件冒泡是指當一個元素上的事件觸發時,父級元素也會收到相同的事件觸發,這種事件傳遞機制有時會為網頁開發帶來麻煩,因此我們需要學習如何有效地阻止事件冒泡。在JavaScript中,我們可以透過使用事件物件的stopPropagation()方法來阻止事件冒泡。該方法可以在事件處理函數中調用,以停止事件繼續傳播到父級元素。

哪些JS事件不會向上傳播? 哪些JS事件不會向上傳播? Feb 19, 2024 am 08:17 AM

JS事件中哪些不會冒泡?在JavaScript中,事件冒泡是指當一個元素觸發了某個事件時,該事件會逐級向上冒泡到更高層的元素,直到冒泡到文檔根節點。然後,事件處理程序會依照冒泡的順序依序執行。然而,並不是所有的事件都會冒泡。有些事件觸發後只會執行目標元素上的事件處理程序,而不會冒泡到更高層的元素上。以下是一些常見的不會冒泡的事件:focus和blur事件:

事件冒泡引發的常見問題與解決方案 事件冒泡引發的常見問題與解決方案 Feb 20, 2024 pm 06:48 PM

事件冒泡(eventbubbling)是指在DOM中,當一個元素上的事件被觸發時,它會向上冒泡到該元素的父級元素,再向上冒泡到更高級別的父級元素,直至冒泡到文檔的根節點。雖然事件冒泡在許多情況下非常有用,但有時它也會引發一些常見的問題。本文將討論一些常見的問題,並提供解決方案。第一個常見問題是多次觸發事件。當一個元素上的事件冒泡到了多個父級元素時,可能會導

See all articles