javascript
html点击冒泡事件,JavaScript 浏览器事件机制(捕获、冒泡、委托)
DOM 樹
文檔對象模型 (DOM),我們把它簡單的理解成一個對象const DOMTree = {}。它是瀏覽器的解析引擎把HTML文檔解析成相應的JavaScript對象。
About elkThe truth about elk.
復制代碼
最終會解析成的樹狀結構對象:
DOM 對象提供了一些接口讓我們可以對節點進行增刪改查。并且還可以讓我們對節點進行綁定事件。
例如我們可以對
節點綁定一個點擊事件。當用戶觸發了點擊事件后,可以讓節點響應一些事情。DOM 事件
DOM 事件提供了人與web進行交互的一種方式。
事件流
如果你單擊了某個按鈕,他們都認為單擊事件不僅僅發生在按鈕上。換句話說,在單擊按鈕的同時,你也單擊了按鈕的容器元素,甚至也單擊了整個頁面。
事件流描述的是從頁面中接收事件的順序。但有意思的是,IE和Netscape開發團隊居然提出了差不多是完全相反的事件流的概念。IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕獲流。
事件冒泡
IE的事件流叫做事件冒泡(event bubbling),即事件開始時由最具體的元素(文檔中嵌套層次最深的那個節點)接收,然后逐級向上傳播到較為不具體的節點(文檔)。
點擊我復制代碼
click 事件首先在
元素上發生,而這個元素就是我們單擊的元素。然后,click事件沿DOM樹向上傳播,在每一級節點上都會發生,直至傳播到document對象。圖片展示了事件冒泡的過程[注意]所有現代瀏覽器都支持事件冒泡。
事件捕獲
事件捕獲的思想是不太具體的節點應該更早接收到事件,而最具體的節點應該最后接收到事件。事件捕獲的用意在于在事件到達預定目標之前捕獲它。
在事件捕獲過程中,document對象首先接收到click事件,然后事件沿DOM樹依次向下,一直傳播到事件的實際目標,即
元素。圖片展示了事件捕獲的過程。DOM 事件流
“DOM2級事件”規定的事件流包括三個階段:事件捕獲階段、處于目標階段和事件冒泡階段。首先發生的是事件捕獲,為截獲事件提供了機會。然后是實際的目標接收到事件。最后一個階段是冒泡階段,可以在這個階段對事件做出響應。
在DOM事件流中,實際的目標(
元素)在捕獲階段不會接收到事件。這意味著在捕獲階段,事件從document到再到后就停止了。下一個階段是“處于目標”階段,于是事件在
上發生,并在事件處理中被看成冒泡階段的一部分。然后,冒泡階段發生,事件又傳播回文檔。
多數支持DOM事件流的瀏覽器都實現了一種特定的行為;即使“DOM2級事件”規范明確要求捕獲階段不會涉及事件目標,但IE9、Safari、Chrome、Firefox和Opera 9.5及更高版本都會在捕獲階段觸發事件對象上的事件。結果,就是有兩個機會在目標對象上面操作事件。
[兼容]IE9、Opera、Firefox、Chrome和Safari都支持DOM事件流;IE8及更早版本不支持DOM事件流。
事件處理程序
事件就是用戶或瀏覽器自身執行的某種動作。諸如 click、load 和 mouseover,都是事件的名字。 而響應某個事件的函數就叫做事件處理程序(或事件偵聽器)。
HTML 事件處理程序
復制代碼
html中定義的事件有權訪問全局作用域中的任何代碼,例如外部引入的JS文件
DOM0級事件處理程序
以DOM0級方式添加的事件處理程序會在事件流的冒泡階段被處理
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert("Clicked");
};
復制代碼
使用DOM0級方法指定的事件處理程序被認為是元素的方法。因此,這時候的事件處理程序是在元素的作用域中運行;
DOM0級事件處理程序的缺點是圍繞著每個事件目標對于每種事件類型只能添加一個事件處理程序。
DOM2級事件處理程序
DOM2級事件處理程序定義了兩個方法用于處理指定和刪除事件處理程序的操作:addEventListener()和removeEventListener()
所有DOM節點中都包含這兩個方法,并且它們都接受3個參數:要處理的事件名、作為事件處理程序的函數和一個布爾值。
最后的布爾值參數如果是true,表示在捕獲階段調用事件處理程序;如果是false,表示在冒泡階段調用事件處理程序。若最后的布爾值不填寫,則和false效果一樣
使用DOM2級事件處理程序的好處是可以添加多個事件處理程序,并按照他們添加的順序觸發
// 添加事件綁定
box.addEventListener("click",function(){
test('123');
},false);
function test(x){box.innerHTML += x;}
// 移除事件綁定
box.removeEventListener('click',test,false);
復制代碼
[兼容]IE9+、Firefox、Safari、Chrome和Opera支持DOM2級事件處理程序
DOM3級事件
在DOM2級事件的基礎上添加了更多的事件類型。
UI事件,當用戶與頁面上的元素交互時觸發,如:load、scroll
焦點事件,當元素獲得或失去焦點時觸發,如:blur、focus
鼠標事件,當用戶通過鼠標在頁面執行操作時觸發如:dblclick、mouseup
滾輪事件,當使用鼠標滾輪或類似設備時觸發,如:mousewheel
文本事件,當在文檔中輸入文本時觸發,如:textInput
鍵盤事件,當用戶通過鍵盤在頁面上執行操作時觸發,如:keydown、keypress
合成事件,當為IME(輸入法編輯器)輸入字符時觸發,如:compositionstart
變動事件,當底層DOM結構發生變化時觸發,如:DOMsubtreeModified
同時DOM3級事件也允許使用者自定義一些事件。
IE中的DOM2級事件處理程序(<=IE8)
IE實現了與DOM中類似的兩個方法:attachEvent()和detachEvent()。
這兩個方法接受相同的兩個參數:事件處理程序名稱與事件處理程序函數。
var btn = document.getElementById("myBtn");
var handler = function(){
alert("Clicked");
};
// 綁定事件
btn.attachEvent("onclick", handler);
// 移除事件
btn.detachEvent("onclick", handler);
復制代碼
由于IE8及更早版本只支持事件冒泡,所以通過attachEvent()添加的事件處理程序都會被添加到冒泡階段。
attachEvent()的第一個參數是"onclick",而非addEventListener()方法中的"click"。
事件處理程序會在全局作用域中運行,因此this等于window。
兼容IE低版本事件處理程序
var EventUtil = {
addHandler: function(element, type, handler){
if (element.addEventListener){
element.addEventListener(type, handler, false);
} else if (element.attachEvent){
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
removeHandler: function(element, type, handler){
if (element.removeEventListener){
element.removeEventListener(type, handler, false);
} else if (element.detachEvent){
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
};
復制代碼
事件的 Event 對象
在觸發DOM上的某個事件時,會產生一個事件對象event,這個對象中包含著所有與事件有關的信息。
包括導致事件的元素、事件的類型以及其他與特定事件相關的信息。例如,鼠標操作導致的事件對象中,會包含鼠標位置的信息,而鍵盤操作導致的事件對象中,會包含與按下的鍵有關的信息。所有瀏覽器都支持event對象,但支持方式不同。
兼容DOM的瀏覽器會將一個event對象傳入到事件處理程序中。無論指定事件處理程序時使用什么方法(DOM0級或DOM2級),都會傳入event對象。
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert(event.type); //"click"
};
btn.addEventListener("click", function(event){
alert(event.type); //"click"
}, false);
復制代碼
通過這個事件對象我們可以做一些事情:
阻止瀏覽器的默認行為
阻止事件冒泡和捕獲
阻止瀏覽器的默認行為
當你點擊a標簽時,瀏覽器有一個默認行為是跳轉鏈接。
當我們想要自己去綁定事件,并且不讓這個默認行為發生就叫阻止瀏覽器的默認行為
var a = document.getElementById("a");
a.addEventListener("click", function(event){
event.preventDefault();
// 事件處理程序內容
}, false);
復制代碼
阻止事件冒泡和捕獲
前面已經講了事件流的行為,那么當我們只想在目標階段處理這個click事件,并且不希望該事件冒泡或捕獲時可以阻止事件冒泡和捕獲
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
alert("Clicked");
event.stopPropagation(); // 阻止事件傳播
};
// document中雖然監聽了點擊事件,由于點擊btn時阻止了事件傳播,因此并不會冒泡到document上
document.body.onclick = function(event){
alert("Body clicked");
};
復制代碼
事件的內存和性能
在JavaScript中,添加到頁面上的事件處理程序數量將直接關系到頁面的整體運行性能。導致這一問題的原因是多方面的。首先,每個函數都是對象,都會占用內存;內存中的對象越多,性能就越差。
事件委托
對“事件處理程序過多”問題的解決方案就是事件委托。事件委托利用了事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。例如,click事件會一直冒泡到document層次。也就是說,我們可以為整個頁面指定一個onclick事件處理程序,而不必給每個可單擊的元素分別添加事件處理程序。
- Go somewhere
- Do something
- Say hi
復制代碼
為3個li都添加相應的點擊事件,這樣會導致性能更差,我們可以只在ul上面添加一個點擊事件,利用冒泡原理來處理事件
var list = document.getElementById("myLinks");
EventUtil.addHandler(list, "click", function(event){
switch(event.target.id){
case "doSomething":
document.title = "I changed the document's title";
break;
case "goSomewhere":
location.href = "http://www.wrox.com";
break;
case "sayHi":
alert("hi");
break;
}
});
復制代碼
事實上React中的事件處理程序都是采用的事件委托的方式。
總結
以上是生活随笔為你收集整理的html点击冒泡事件,JavaScript 浏览器事件机制(捕获、冒泡、委托)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (3)verilog与VHDL两种语言编
- 下一篇: gradle idea java ssm