a标签点击事件_DOM事件机制
前言
本文主要介紹DOM事件級別、DOM事件模型、事件流、事件代理和Event對象常見的應(yīng)用,希望對你們有些幫助和啟發(fā)!
一、DOM事件級別
DOM級別一共可以分為四個(gè)級別:DOM0級、DOM1級、DOM2級和DOM3級。而DOM事件分為3個(gè)級別:DOM 0級事件處理,DOM 2級事件處理和DOM 3級事件處理。由于DOM 1級中沒有事件的相關(guān)內(nèi)容,所以沒有DOM 1級事件。
1.DOM 0級事件
el.οnclick=function(){}
//?例1var?btn?=?document.getElementById('btn');
?btn.onclick?=?function(){
?????alert(this.innerHTML);
?}
當(dāng)希望為同一個(gè)元素/標(biāo)簽綁定多個(gè)同類型事件的時(shí)候(如給上面的這個(gè)btn元素綁定3個(gè)點(diǎn)擊事件),是不被允許的。DOM0事件綁定,給元素的事件行為綁定方法,這些方法都是在當(dāng)前元素事件行為的冒泡階段(或者目標(biāo)階段)執(zhí)行的。
2.DOM 2級事件
el.addEventListener(event-name, callback, useCapture)
event-name: 事件名稱,可以是標(biāo)準(zhǔn)的DOM事件
callback: 回調(diào)函數(shù),當(dāng)事件觸發(fā)時(shí),函數(shù)會被注入一個(gè)參數(shù)為當(dāng)前的事件對象 event
useCapture: 默認(rèn)是false,代表事件句柄在冒泡階段執(zhí)行
var?btn?=?document.getElementById('btn');
btn.addEventListener("click",?test,?false);
function?test(e){
????e?=?e?||?window.event;
????alert((e.target?||?e.srcElement).innerHTML);
????btn.removeEventListener("click",?test)
}
//IE9-:attachEvent()與detachEvent()。
//IE9+/chrom/FF:addEventListener()和removeEventListener()
IE9以下的IE瀏覽器不支持 addEventListener()和removeEventListener(),使用 attachEvent()與detachEvent() 代替,因?yàn)镮E9以下是不支持事件捕獲的,所以也沒有第三個(gè)參數(shù),第一個(gè)事件名稱前要加on。
3.DOM 3級事件
在DOM 2級事件的基礎(chǔ)上添加了更多的事件類型。
UI事件,當(dāng)用戶與頁面上的元素交互時(shí)觸發(fā),如:load、scroll
焦點(diǎn)事件,當(dāng)元素獲得或失去焦點(diǎn)時(shí)觸發(fā),如:blur、focus
鼠標(biāo)事件,當(dāng)用戶通過鼠標(biāo)在頁面執(zhí)行操作時(shí)觸發(fā)如:dblclick、mouseup
滾輪事件,當(dāng)使用鼠標(biāo)滾輪或類似設(shè)備時(shí)觸發(fā),如:mousewheel
文本事件,當(dāng)在文檔中輸入文本時(shí)觸發(fā),如:textInput
鍵盤事件,當(dāng)用戶通過鍵盤在頁面上執(zhí)行操作時(shí)觸發(fā),如:keydown、keypress
合成事件,當(dāng)為IME(輸入法編輯器)輸入字符時(shí)觸發(fā),如:compositionstart
變動事件,當(dāng)?shù)讓覦OM結(jié)構(gòu)發(fā)生變化時(shí)觸發(fā),如:DOMsubtreeModified
同時(shí)DOM3級事件也允許使用者自定義一些事件。
二、DOM事件模型和事件流
DOM事件模型分為捕獲和冒泡。一個(gè)事件發(fā)生后,會在子元素和父元素之間傳播(propagation)。這種傳播分成三個(gè)階段。
(1)捕獲階段:事件從window對象自上而下向目標(biāo)節(jié)點(diǎn)傳播的階段;
(2)目標(biāo)階段:真正的目標(biāo)節(jié)點(diǎn)正在處理事件的階段;
(3)冒泡階段:事件從目標(biāo)節(jié)點(diǎn)自下而上向window對象傳播的階段。
DOM事件捕獲的具體流程
捕獲是從上到下,事件先從window對象,然后再到document(對象),然后是html標(biāo)簽(通過document.documentElement獲取html標(biāo)簽),然后是body標(biāo)簽(通過document.body獲取body標(biāo)簽),然后按照普通的html結(jié)構(gòu)一層一層往下傳,最后到達(dá)目標(biāo)元素。
而事件冒泡的流程剛好是事件捕獲的逆過程。
接下來我們看個(gè)事件冒泡的例子:
"outer">"inner">
......
window.onclick?=?function()?{
????console.log('window');
};
document.onclick?=?function()?{
????console.log('document');
};
document.documentElement.onclick?=?function()?{
????console.log('html');
};
document.body.onclick?=?function()?{
????console.log('body');
}
outer.onclick?=?function(ev)?{
????console.log('outer');
};
inner.onclick?=?function(ev)?{
????console.log('inner');
};
正如我們上面提到的onclick給元素的事件行為綁定方法都是在當(dāng)前元素事件行為的冒泡階段(或者目標(biāo)階段)執(zhí)行的。
三、事件代理(事件委托)
由于事件會在冒泡階段向上傳播到父節(jié)點(diǎn),因此可以把子節(jié)點(diǎn)的監(jiān)聽函數(shù)定義在父節(jié)點(diǎn)上,由父節(jié)點(diǎn)的監(jiān)聽函數(shù)統(tǒng)一處理多個(gè)子元素的事件。這種方法叫做事件的代理(delegation)。
1.優(yōu)點(diǎn)
減少內(nèi)存消耗,提高性能
假設(shè)有一個(gè)列表,列表之中有大量的列表項(xiàng),我們需要在點(diǎn)擊每個(gè)列表項(xiàng)的時(shí)候響應(yīng)一個(gè)事件
//?例4<ul?id="list">
??<li>item?1li>
??<li>item?2li>
??<li>item?3li>
??......
??<li>item?nli>
ul>
如果給每個(gè)列表項(xiàng)一一都綁定一個(gè)函數(shù),那對于內(nèi)存消耗是非常大的,效率上需要消耗很多性能。借助事件代理,我們只需要給父容器ul綁定方法即可,這樣不管點(diǎn)擊的是哪一個(gè)后代元素,都會根據(jù)冒泡傳播的傳遞機(jī)制,把容器的click行為觸發(fā),然后把對應(yīng)的方法執(zhí)行,根據(jù)事件源,我們可以知道點(diǎn)擊的是誰,從而完成不同的事。
動態(tài)綁定事件
在很多時(shí)候,我們需要通過用戶操作動態(tài)的增刪列表項(xiàng)元素,如果一開始給每個(gè)子元素綁定事件,那么在列表發(fā)生變化時(shí),就需要重新給新增的元素綁定事件,給即將刪去的元素解綁事件,如果用事件代理就會省去很多這樣麻煩。
2.如何實(shí)現(xiàn)
接下來我們來實(shí)現(xiàn)上例中父層元素 #list 下的 li 元素的事件委托到它的父層元素上:
//?給父層元素綁定事件document.getElementById('list').addEventListener('click',?function?(e)?{
??//?兼容性處理
??var?event?=?e?||?window.event;
??var?target?=?event.target?||?event.srcElement;
??//?判斷是否匹配目標(biāo)元素
??if?(target.nodeName.toLocaleLowerCase?===?'li')?{
????console.log('the?content?is:?',?target.innerHTML);
??}
});
四、Event對象常見的應(yīng)用
event. preventDefault()
如果調(diào)用這個(gè)方法,默認(rèn)事件行為將不再觸發(fā)。什么是默認(rèn)事件呢?例如表單一點(diǎn)擊提交按鈕(submit)跳轉(zhuǎn)頁面、a標(biāo)簽?zāi)J(rèn)頁面跳轉(zhuǎn)或是錨點(diǎn)定位等。
很多時(shí)候我們使用a標(biāo)簽僅僅是想當(dāng)做一個(gè)普通的按鈕,點(diǎn)擊實(shí)現(xiàn)一個(gè)功能,不想頁面跳轉(zhuǎn),也不想錨點(diǎn)定位。
//方法一:<a?href="javascript:;">鏈接a>
也可以通過JS方法來阻止,給其click事件綁定方法,當(dāng)我們點(diǎn)擊A標(biāo)簽的時(shí)候,先觸發(fā)click事件,其次才會執(zhí)行自己的默認(rèn)行為
//方法二:<a?id="test"?href="http://www.cnblogs.com">鏈接a>
<script>
test.onclick?=?function(e){
????e?=?e?||?window.event;return?false;
}script>
//方法三:
<a?id="test"?href="http://www.cnblogs.com">鏈接a>
<script>
test.onclick?=?function(e){
????e?=?e?||?window.event;
????e.preventDefault();
}script>
接下來我們看個(gè)例子:輸入框最多只能輸入六個(gè)字符,如何實(shí)現(xiàn)?
//?例5?"text"?id='tempInp'>
?<script>
????tempInp.onkeydown?=?function(ev)?{
????????ev?=?ev?||?window.event;let?val?=?this.value.trim()?//trim去除字符串首位空格(不兼容)//?this.value=this.value.replace(/^?+|?+$/g,'')?兼容寫法let?len?=?val.lengthif?(len?>=?6)?{this.value?=?val.substr(0,?6);//阻止默認(rèn)行為去除特殊按鍵(DELETE\BACK-SPACE\方向鍵...)let?code?=?ev.which?||?ev.keyCode;if?(!/^(46|8|37|38|39|40)$/.test(code))?{
????????????????ev.preventDefault()
????????????}
????????}
????}script>
event.stopPropagation() & event.stopImmediatePropagation()
event.stopPropagation() 方法阻止事件冒泡到父元素,阻止任何父事件處理程序被執(zhí)行。上面提到事件冒泡階段是指事件從目標(biāo)節(jié)點(diǎn)自下而上向window對象傳播的階段。
我們在例4的inner元素click事件上,添加event.stopPropagation()這句話后,就阻止了父事件的執(zhí)行,最后只打印了'inner'。
????console.log('inner');
????ev.stopPropagation();
};
stopImmediatePropagation 既能阻止事件向父元素冒泡,也能阻止元素同事件類型的其它監(jiān)聽器被觸發(fā)。而 stopPropagation 只能實(shí)現(xiàn)前者的效果。我們來看個(gè)例子:
??"btn">click?me?to?stop?propagation
......
const?btn?=?document.querySelector('#btn');
btn.addEventListener('click',?event?=>?{
??console.log('btn?click?1');
??event.stopImmediatePropagation();
});
btn.addEventListener('click',?event?=>?{
??console.log('btn?click?2');
});
document.body.addEventListener('click',?()?=>?{
??console.log('body?click');
});
//?btn?click?1
如上所示,使用 stopImmediatePropagation后,點(diǎn)擊按鈕時(shí),不僅body綁定事件不會觸發(fā),與此同時(shí)按鈕的另一個(gè)點(diǎn)擊事件也不觸發(fā)。
event.target & event.currentTarget
老實(shí)說這兩者的區(qū)別,并不好用文字描述,我們先來看個(gè)例子:
<div?id="a">??<div?id="b">
????<div?id="c"><div?id="d">div>div>
??div>
div>
<script>document.getElementById('a').addEventListener('click',?function(e)?{console.log('target:'?+?e.target.id?+?'¤tTarget:'?+?e.currentTarget.id
????)
??})document.getElementById('b').addEventListener('click',?function(e)?{console.log('target:'?+?e.target.id?+?'¤tTarget:'?+?e.currentTarget.id
????)
??})document.getElementById('c').addEventListener('click',?function(e)?{console.log('target:'?+?e.target.id?+?'¤tTarget:'?+?e.currentTarget.id
????)
??})document.getElementById('d').addEventListener('click',?function(e)?{console.log('target:'?+?e.target.id?+?'¤tTarget:'?+?e.currentTarget.id
????)
??})script>
當(dāng)我們點(diǎn)擊最里層的元素d的時(shí)候,會依次輸出:
target:d¤tTarget:dtarget:d¤tTarget:c
target:d¤tTarget:b
target:d¤tTarget:a
從輸出中我們可以看到,event.target指向引起觸發(fā)事件的元素,而event.currentTarget則是事件綁定的元素,只有被點(diǎn)擊的那個(gè)目標(biāo)元素的event.target才會等于event.currentTarget。也就是說,event.currentTarget始終是監(jiān)聽事件者,而event.target是事件的真正發(fā)出者。
五、參考文章
DOM級別與DOM事件
DOM事件機(jī)制解惑
事件模型
JavaScript 事件委托詳解
JavaScript 事件的學(xué)與記:stopPropagation 和 stopImmediatePropagation
event.target和event.currentTarget的區(qū)別
總結(jié)
以上是生活随笔為你收集整理的a标签点击事件_DOM事件机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV3计算机视觉:Python实
- 下一篇: SQLServer知识:sqlcmd用法