詳解JavaScript 事件流
事件
HTML中與javascript交互是通過事件驅(qū)動(dòng)來實(shí)現(xiàn)的,例如鼠標(biāo)點(diǎn)擊事件、頁面的滾動(dòng)事件onscroll等等,可以向文檔或者文檔中的元素添加事件偵聽器來預(yù)訂事件。想要知道這些事件是在什么時(shí)候進(jìn)行調(diào)用的,就需要了解一下“事件流”的概念。
事件流
事件流描述的就是從頁面中接收事件的順序。而早期的IE和Netscape提出了完全相反的事件流概念,IE事件流是事件冒泡,而Netscape的事件流就是事件捕獲。
事件流類別
事件冒泡
即從下至上,從目標(biāo)觸發(fā)的元素逐級(jí)向上傳播,直到window對(duì)象。
事件捕獲
即從上至下,從document逐級(jí)向下傳播到目標(biāo)元素。
后來ECMAScript在DOM2中對(duì)事件流進(jìn)行了進(jìn)一步規(guī)范,基本上就是上述二者的結(jié)合。
DOM2級(jí)事件規(guī)定的事件流包括三個(gè)階段:
- 事件捕獲階段
- 處于目標(biāo)階段
- 事件冒泡階段
注意⚠️:先捕獲后冒泡,但是在目標(biāo)節(jié)點(diǎn)上誰寫在前面誰先執(zhí)行。但是在目標(biāo)元素上不區(qū)分冒泡還是捕獲,按綁定的順序來執(zhí)行。
DOM事件級(jí)別
分為四個(gè)級(jí)別
DOM0:不是W3C規(guī)范。
DOM1:開始是W3C規(guī)范。專注于HTML文檔和XML文檔。
DOM2:對(duì)DOM1增加了樣式表對(duì)象模型
DOM3:對(duì)DOM2增加了內(nèi)容模型 (DTD 、Schemas) 和文檔驗(yàn)證。
DOM0級(jí)
DOM0級(jí)事件具有極好的跨瀏覽器優(yōu)勢(shì),會(huì)以最快的速度綁定。綁定方式有如下兩種
行內(nèi)綁定(內(nèi)聯(lián)模型)
將函數(shù)名直接作為html標(biāo)簽中屬性的屬性值。
<div onclick="btnClick()">按鈕</div> <script> function btnClick(){ console.log("hello"); } </script>
動(dòng)態(tài)綁定(腳本模型)
通過在JS中選中某個(gè)節(jié)點(diǎn),然后給節(jié)點(diǎn)添加onclick屬性
<div id="btn">按鈕</div> <script> var btn = document.getElementById("btn"); btn.onclick = function(){ console.log("點(diǎn)擊"); } </script>
注意⚠️
- DOM0級(jí)同一個(gè)節(jié)點(diǎn)只能添加一次同類型事件,后添加的同類型事件會(huì)覆蓋前面的事件
- DOM0級(jí)只支持冒泡
DOM1級(jí)
其中DOM1級(jí)事件處理標(biāo)準(zhǔn)中并沒有定義事件相關(guān)的內(nèi)容,所以沒有所謂的DOM1事件處理
DOM2級(jí)
DOM2級(jí)定義了兩個(gè)事件處理程序。(觀察者模式)
- addEventListener() ---添加事件偵聽器
- removeEventListener() ---刪除事件偵聽器
函數(shù)均有3個(gè)參數(shù), 第一個(gè)參數(shù)是要處理的事件名 第二個(gè)參數(shù)是作為事件處理程序的函數(shù) 第三個(gè)參數(shù)是一個(gè)boolean值,默認(rèn)false表示使用冒泡機(jī)制,true表示捕獲機(jī)制。
<div id="btn">按鈕</div> <script> var btn=document.getElementById("btn"); btn.addEventListener("click",hello,false); btn.addEventListener("click",helloagain,false); function hello(){ console.log("hello"); } function helloagain(){ console.log("hello again"); } </script> // 點(diǎn)擊后結(jié)果: // hello // hello again
注意⚠️
如果定義了一模一樣的監(jiān)聽方法時(shí),是會(huì)發(fā)生覆蓋的。
<div id="btn">點(diǎn)擊</div> <script> var btn=document.getElementById("btn"); btn.addEventListener("click",hello,false); btn.addEventListener("click",hello,false); function hello(){ console.log("hello"); } </script> // 點(diǎn)擊后結(jié)果: // hello
DOM3級(jí)
對(duì)DOM2增加了內(nèi)容模型 (DTD 、Schemas) 和文檔驗(yàn)證。定義了一些新的事件,比如鍵盤事件,還可以自定義事件。
自定義事件
自定義事件不是由DOM原生觸發(fā)的,它的目的是讓開發(fā)人員創(chuàng)建自己的事件。要?jiǎng)?chuàng)建的自定義事件可以由createEvent("CustomEvent"); 返回的對(duì)象有一個(gè)initCustomEvent()方法接收如下四個(gè)參數(shù)。
- type:字符串,觸發(fā)的事件類型,自定義。例如 “keyDown”,“selectedChange”;
- bubble(布爾值):標(biāo)示事件是否應(yīng)該冒泡;
- cancelable(布爾值):標(biāo)示事件是否可以取消;
- detail(對(duì)象):任意值,保存在event對(duì)象的detail屬性中;
可以像分配其他事件一樣在DOM中分派創(chuàng)建的自定義事件對(duì)象。如:
var div = document.getElementById("myDiv"); EventUtil.addEventHandler(div,"myEvent", function () { alert("div myEvent!"); }); EventUtil.addEventHandler(document,"myEvent",function(){ alert("document myEvent!"); }); if(document.implementation.hasFeature("CustomEvents","3.0")){ var e = document.createEvent("CustomEvent"); e.initCustomEvent("myEvent",true,false,"hello world!"); div.dispatchEvent(e); }
這個(gè)例子中創(chuàng)建了一個(gè)冒泡事件“myEvent”。而event.detail的值被設(shè)置成了一個(gè)簡單的字符串,然后在div和document上偵聽該事件,因?yàn)樵趇nitCustomEvent中設(shè)置了事件冒泡。所以當(dāng)div激發(fā)該事件時(shí),瀏覽器會(huì)將該事件冒泡到document。
阻止冒泡
stopPropagation函數(shù)
btn.addEventListener('click',function(ev){ ev.stopPropagation(); console.log('阻止冒泡') }, false)
事件委托(事件代理)
原理
如果有多個(gè)DOM節(jié)點(diǎn)需要監(jiān)聽事件的情況下,給每個(gè)DOM綁定監(jiān)聽函數(shù),會(huì)極大的影響頁面的性能,因?yàn)槲覀兺ㄟ^事件委托來進(jìn)行優(yōu)化,事件委托利用的就是冒泡的原理。
<ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul> <script> var li_list = document.getElementsByTagName('li') for(let index = 0;index<li_list.length;index++){ li_list[index].addEventListener('click', function(ev){ console.log(ev.currentTarget.innerHTML) }) } </script>
正常情況我們給每一個(gè)li都會(huì)綁定一個(gè)事件,但是如果這時(shí)候li是動(dòng)態(tài)渲染的,數(shù)據(jù)又特別大的時(shí)候,每次渲染后(有新增的情況)我們還需要重新來綁定,又繁瑣又耗性能;這時(shí)候我們可以將綁定事件委托到li的父級(jí)元素,即ul。
var ul_dom = document.getElementsByTagName('ul') ul_dom[0].addEventListener('click', function(ev){ console.log(ev.target.innerHTML) })
target和currentTarget區(qū)別:
- target返回觸發(fā)事件的元素,不一定是綁定事件的元素
- currentTarget返回的是綁定事件的元素
優(yōu)點(diǎn)
- 提高性能: 每一個(gè)函數(shù)都會(huì)占用內(nèi)存空間,只需添加一個(gè)事件處理程序代理所有事件,所占用的內(nèi)存空間更少。
- 動(dòng)態(tài)監(jiān)聽: 使用事件委托可以自動(dòng)綁定動(dòng)態(tài)添加的元素,即新增的節(jié)點(diǎn)不需要主動(dòng)添加也可以一樣具有和其他元素一樣的事件。
以上就是詳解JavaScript 事件流的詳細(xì)內(nèi)容,更多關(guān)于JavaScript 事件流的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript原始數(shù)據(jù)類型Symbol的用法詳解
Symbol是ES6中引入的一種新的基本數(shù)據(jù)類型,用于表示一個(gè)獨(dú)一無二的值。它是JavaScript中的第七種數(shù)據(jù)類型。本文將詳細(xì)講講Symbol的使用,需要的可以參考一下2022-11-11獲取陰歷(農(nóng)歷)和當(dāng)前日期的js代碼
這篇文章主要為大家詳細(xì)介紹了獲取陰歷(農(nóng)歷)日期的js代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-02-02IOS中safari下的select下拉菜單文字過長不換行的解決方法
今天在項(xiàng)目開發(fā)中遇到一個(gè)問題safari下的select下拉菜單文字過長不換行問題,最終我用<optgroup>標(biāo)簽解決此問題,下面小編把實(shí)現(xiàn)思路分享給大家供大家參考2016-09-09HTML頁面,測(cè)試JS對(duì)C函數(shù)的調(diào)用簡單實(shí)例
下面小編就為大家?guī)硪黄狧TML頁面,測(cè)試JS對(duì)C函數(shù)的調(diào)用簡單實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-08-08javascript實(shí)現(xiàn)復(fù)選框超過限制即彈出警告框的方法
這篇文章主要介紹了javascript實(shí)現(xiàn)復(fù)選框超過限制即彈出警告框的方法,涉及復(fù)選框及警告框的操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02JavaScript操作DOM元素的childNodes和children區(qū)別
這篇文章主要介紹了JavaScript操作DOM元素的childNodes和children區(qū)別,本文直接給出測(cè)試代碼和運(yùn)行效果來講解它們之間的區(qū)別,需要的朋友可以參考下2015-04-04微信小程序 scroll-view 水平滾動(dòng)實(shí)現(xiàn)過程解析
這篇文章主要介紹了微信小程序 scroll-view 水平滾動(dòng)實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10基于BootStrap Metronic開發(fā)框架經(jīng)驗(yàn)小結(jié)【一】框架總覽及菜單模塊的處理
這篇文章主要介紹了基于BootStrap Metronic開發(fā)框架經(jīng)驗(yàn)小結(jié)【一】框架總覽及菜單模塊的處理的相關(guān)資料,小編認(rèn)為非常具有參考借鑒價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-05-05