日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > HTML >内容正文

HTML

浏览器事件流

發(fā)布時(shí)間:2023/12/20 HTML 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浏览器事件流 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

事件流描述的是從頁(yè)面中接受事件的順序。但有意思的是,IE和Netscape開發(fā)團(tuán)隊(duì)居然提出了兩個(gè)截然相反的事件流概念。

  1、IE的事件流是 事件冒泡流,

  ?2、標(biāo)準(zhǔn)的瀏覽器事件流是 事件捕獲流。

? ? ?不過addEventLister給出了第三個(gè)參數(shù)同時(shí)支持冒泡與捕獲,下文將介紹

?

事件冒泡

ie 的事件流叫事件冒泡,也就是說事件的傳播為:從事件開始的具體元素,一級(jí)級(jí)往上傳播到較為不具體的節(jié)點(diǎn)。案例如下:

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>事件冒泡</title> </head> <body><div><p>點(diǎn)我</p></div> </body> </html>

當(dāng)我們點(diǎn)擊P元素時(shí),事件是這樣傳播的:

(1) p

(2) div

(3) body

(4) html

(5) document

現(xiàn)代瀏覽器都支持事件冒泡,IE9、Firefox、Chrome和Safari則將事件一直冒泡到window對(duì)象。

?

事件捕獲

? ?Netscape團(tuán)隊(duì)提出的另一種事件流叫做事件捕獲。它的原理剛好和事件冒泡相反,它的用意在于在事件到達(dá)預(yù)定目標(biāo)之前捕獲它,而最具體的節(jié)點(diǎn)應(yīng)該是最后才接收到事件的。

比如還是上面的案例,當(dāng)點(diǎn)擊P元素時(shí),事件的傳播方向就變成了這樣:

(1) document

(2) html

(3) body

(4) div

(5) p

?

IE9、Firefox、Chrome和Safari目前也支持這種事件流模型,但是有些老版本的瀏覽器不支持,所以很少人使用事件捕獲,而是用事件冒泡的多一點(diǎn)。

?

DOM事件流

?  "DOM2級(jí)事件"規(guī)定的事件流包括三個(gè)階段:事件捕獲階段、處于目標(biāo)階段、事件冒泡階段。

  首先發(fā)生的事件捕獲,為截獲事件提供機(jī)會(huì)。然后是實(shí)際的目標(biāo)接受事件。最后一個(gè)階段是時(shí)間冒泡階段,可以在這個(gè)階段對(duì)事件做出響應(yīng)。以前面的例子,則會(huì)按下圖順序觸發(fā)事件。

  圖1-1(圖片來源于課本,所以沒有上面案例的p標(biāo)簽)

  在DOM事件流中,事件的目標(biāo)在捕獲階段不會(huì)接受到事件。這意味著在捕獲階段,事件從document到p后就定停止了。

  下一個(gè)階段是處于目標(biāo)階段,于是事件在p上發(fā)生,并在事件處理中被看成冒泡階段的一部分。然后,冒泡階段發(fā)生,事件又傳播回document。??

? ? ?多數(shù)支持DOM事件流的瀏覽器都實(shí)現(xiàn)了一種特定的行為;即使“DOM2級(jí)事件”規(guī)范明確要求捕獲階段不會(huì)涉及事件目標(biāo),但I(xiàn)E9、Safari、Chrome、Firefox和Opera9.5及更高版本都會(huì)在捕獲階段觸發(fā)事件對(duì)象上的事件。結(jié)果,就是有兩個(gè)機(jī)會(huì)在目標(biāo)對(duì)象上操作事件

?

事件處理程序

事件就是用戶或者瀏覽器自身執(zhí)行某種動(dòng)作,比如click、load、mouseover。 而響應(yīng)某個(gè)事件的函數(shù)就叫做事件處理程序(事件監(jiān)聽器),事件處理程序的名字以on開頭,click=>onclick、load=>onloadDOM2提供了兩個(gè)方法來讓我們處理和刪除事件處理程序的操作:addEventListener()和removeEventListener btn.addEventListener(eventType, function () { }, false);該方法應(yīng)用至dom節(jié)點(diǎn) 第一個(gè)參數(shù)為事件名 第二個(gè)為事件處理程序 第三個(gè)為布爾值,true為事件捕獲階段調(diào)用事件處理程序,false為事件冒泡階段調(diào)用事件處理程序

?

使用例子如下:

var btn = document.getElementById(‘btn‘);btn.addEventListener(‘click‘, function () {alert(‘事件捕獲‘);}, true);btn.addEventListener(‘click‘, function () {alert(‘事件冒泡‘);}, false);

依次彈出“事件捕獲”和“事件冒泡”,在這里的第一反應(yīng)就是,他們有先后順序嗎?

于是我反過來寫:

var btn = document.getElementById(‘btn‘);btn.addEventListener(‘click‘, function () {alert(‘事件冒泡‘);}, false);btn.addEventListener(‘click‘, function () {alert(‘事件捕獲‘);}, true);

依次彈出的是:“事件冒泡”和“事件捕獲”;到底有沒有先后順序呢?繼續(xù)往下走

這次是這樣的寫法:

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>事件冒泡</title> </head> <body><div><p id="parEle">我是父元素 <span id="sonEle">我是子元素</span></p></div> </body> </html> <script type="text/javascript"> var sonEle = document.getElementById(‘sonEle‘); var parEle = document.getElementById(‘parEle‘);parEle.addEventListener(‘click‘, function () {alert(‘父級(jí) 冒泡‘); }, false); parEle.addEventListener(‘click‘, function () {alert(‘父級(jí) 捕獲‘); }, true);sonEle.addEventListener(‘click‘, function () {alert(‘子級(jí)冒泡‘); }, false); sonEle.addEventListener(‘click‘, function () {alert(‘子級(jí)捕獲‘); }, true);</script>

當(dāng)點(diǎn)擊“我是子元素” 時(shí),彈出的順序是:“父級(jí)捕獲”--》“子級(jí)冒泡”--》“子集捕獲”--》“父集冒泡”;

這里可以說明,當(dāng)點(diǎn)擊子元素時(shí),父級(jí)的執(zhí)行順序是先捕獲,后冒泡的。

  綜合前面的代碼,我們可以得出一個(gè)小小的結(jié)論:

  當(dāng)容器元素及嵌套元素,即在捕獲階段又在冒泡階段調(diào)用事件處理程序時(shí):事件按DOM事件流的順序執(zhí)行事件處理程序,也就是如圖1-1所示

  且當(dāng)事件處于目標(biāo)階段時(shí),事件調(diào)用順序決定于綁定事件的書寫順序,按上面的例子為,先調(diào)用冒泡階段的事件處理程序,再調(diào)用捕獲階段的事件處理程序。依次alert出“子集冒泡”,“子集捕獲”。

?

刪除一個(gè)事件處理程序,用removeEventListener。例:

var btn=document.getElementById(‘myBtn‘); var myFn=function(){alert(this.id); } btn.addEventListener(‘click‘,myFn,false); btn.removeEventListener(‘click‘,myFn,false);

?

注意點(diǎn):為了最大限度的兼容,大多是情況下都是將事件處理程序添加到事件冒泡階段。不是特別需要,不建議在事件捕獲階段注冊(cè)事件處理程序

?

兼容ie瀏覽器寫法:

?

ie添加和刪除事件處理程序的寫法有點(diǎn)小區(qū)別,所以用以下代碼可以做個(gè)兼容性處理:

var EventUtil = {addHandler: function (el, type, handler) {if (el.addEventListener) {el.addEventListener(type, handler, false);} else {el.attachEvent(‘on‘ + type, handler);}},removeHandler: function (el, type, handler) {if (el.removeEventListener) {el.removeEventListerner(type, handler, false);} else {el.detachEvent(‘on‘ + type, handler);}} };

用法和前面的類似:

EventUtil.addHandler(‘btn‘,‘click‘,handler);

?

?

事件對(duì)象

觸發(fā)dom上的某個(gè)事件時(shí),會(huì)產(chǎn)生一個(gè)事件對(duì)象,里面包含著所有和事件有關(guān)的信息。

比較常用的有以下幾個(gè):

currentTarget 事件處理程序當(dāng)前正在處理事件的那個(gè)元素(始終等于this)preventDefault 取消事件默認(rèn)行為,比如鏈接的跳轉(zhuǎn)stopPropagation 取消事件冒泡target 事件的目標(biāo)

  

兼容ie的事件對(duì)象:

var EventUtil = {addHandler: function (el, type, handler) {if (el.addEventListener) {el.addEventListener(type, handler, false);} else if (el.attachEvent) {el.attachEvent(‘on‘ + type, handler);} else {el[‘on‘ + type] = handler;}},removeHandler: function (el, type, handler) {if (el.removeEventListener) {el.removeEventListerner(type, handler, false);} else if (el.detachEvent) {el.detachEvent(‘on‘ + type, handler);} else {el[‘on‘ + type] = null;}},getEvent: function (e) {return e ? e : window.event;},getTarget: function (e) {return e.target ? e.target : e.srcElement;},preventDefault: function (e) {if (e.preventDefault) {e.preventDefault();} else {e.returnValue = false;}},stopPropagation: function (e) {if (e.stopPropagation) {e.stopPropagation();} else {e.cancelBubble = true;}} };

?

?

其他

?

html5事件之 beforeunload

在頁(yè)面卸載前觸發(fā),就像編輯博客園文章未保存是彈出的提示框一樣。

?

html5事件之 DOMContentLoaded事件

支持頁(yè)面下載前添加事件,而不需要等待圖片,css文件,或者其他文件加載完畢才執(zhí)行。可以讓用戶能夠盡早的與用戶進(jìn)行交互。

EventUtil.addHandler(document,‘DOMContentLoaded‘,function(){alert(‘我可以先執(zhí)行,哈哈‘) })

?

事件委托:

? ?每個(gè)函數(shù)都是對(duì)象,都會(huì)占用內(nèi)存,內(nèi)存中的對(duì)象越多,性能就越差。對(duì)事件處理程序過多問題的解決方案就是事件委托。

? ?事件委托利用事件冒泡,只指定一個(gè)事件處理程序即可,就可以管理某一個(gè)類型的所有事件。例如:

有三個(gè)li,都需要一個(gè)click事件,此時(shí)不需要給每個(gè)li都綁定click事件,主要給他的父級(jí) ul增加一個(gè)綁定事件即可。這樣點(diǎn)擊li,利用冒泡,直接觸發(fā)ul的click,只要判斷是哪個(gè)li的id

點(diǎn)擊即可。而不需要三個(gè)li都綁定click事件。

<ul id="myLinks"><li id="myLi1">text1</li><li id="myLi2">text2</li><li id="myLi3">text3</li> </ul>

?

事件委托原理:事件冒泡機(jī)制。 優(yōu)點(diǎn):1.可以大量節(jié)省內(nèi)存占用,減少事件注冊(cè)。比如ul上代理所有l(wèi)i的click事件就很不錯(cuò)。 2.可以實(shí)現(xiàn)當(dāng)新增子對(duì)象時(shí),無需再對(duì)其進(jìn)行事件綁定,對(duì)于動(dòng)態(tài)內(nèi)容部分尤為合適 缺點(diǎn):事件代理的常用應(yīng)用應(yīng)該僅限于上述需求,如果把所有事件都用事件代理,可能會(huì)出現(xiàn)事件誤判。即本不該被觸發(fā)的事件被綁定上了事件。

二、事件委托如何工作?

我們現(xiàn)在的疑問是:ul元素如何知道li元素點(diǎn)擊了呢?

很簡(jiǎn)單,由于所有l(wèi)i元素都是ul元素的子節(jié)點(diǎn),故他們的事件會(huì)冒泡,無論點(diǎn)擊哪個(gè)li元素,實(shí)際上都相當(dāng)于點(diǎn)擊了ul元素。

現(xiàn)在產(chǎn)生了另一個(gè)問題:ul元素如何知道是在哪個(gè)li元素上點(diǎn)擊的呢?

我們很容易想到,在ul的事件處理程序中檢測(cè)事件對(duì)象的target屬性,就可以得到真正點(diǎn)擊的目標(biāo)元素。

三、事件委托的優(yōu)點(diǎn)

首先,我們看到添加的事件處理程序減少,可以只有一個(gè)事件處理程序。由于每個(gè)函數(shù)都是對(duì)象,對(duì)象會(huì)占用內(nèi)存,內(nèi)存的占用關(guān)系到性能。因此第一個(gè)優(yōu)點(diǎn)是:

減少了內(nèi)存占用,性能更好;

在訪問DOM方面,也使得DOM訪問次數(shù)減少。試想一下,如果要為許多的DOM元素綁定事件,自然需要多次訪問DOM元素,設(shè)置事件處理程序所需時(shí)間更長(zhǎng),整個(gè)頁(yè)面就緒需要的時(shí)間越多。因此第二個(gè)優(yōu)點(diǎn)是:

設(shè)置事件處理程序所需時(shí)間更少,加快了整個(gè)頁(yè)面的交互就緒時(shí)間。

假使我們將事件處理程序綁定到document對(duì)象上,只要可單擊的元素呈現(xiàn)在頁(yè)面上,就可以立即具備適當(dāng)?shù)墓δ堋<催€會(huì)有一個(gè)額外的優(yōu)點(diǎn):

document很快就可以訪問,而且可以在頁(yè)面生命周期的任何時(shí)點(diǎn)添加事件處理程序,而不用等待其他事件完成如DOMContentLoaded、load事件。

總結(jié)

以上是生活随笔為你收集整理的浏览器事件流的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。