DOM(Document Object Model) 即文檔對(duì)象模型蟀拷,是針對(duì)HTML和XML文檔的一個(gè)API危尿,DOM描繪了一個(gè)層次化的節(jié)點(diǎn)樹示损,允許開發(fā)人員進(jìn)行添加寿弱、移除和修改頁面的某一部分犯眠。
一、DOM事件的級(jí)別
-
DOM0 點(diǎn)擊事件的JS中寫法是:
element.onclick=function(){ }
症革,如果在HTML中就是onclick
屬性上加一個(gè)JS語句筐咧。
刪除DOM0事件處理程序,只要將對(duì)應(yīng)事件屬性置為null即可噪矛,即element.onclick=null
量蕊。 -
DOM2 新增的點(diǎn)擊事件JS中寫法是:
element.addEventListener('click', function(){}, false)
。最后一個(gè)參數(shù)為true
的時(shí)候表示在捕獲階段調(diào)用程序艇挨,如果是false残炮,表示在冒泡階段調(diào)用事件處理程序,不填則默認(rèn)為false
缩滨。
刪除DOM2事件處理程序势就,用removeEventListener
實(shí)現(xiàn)。
IE中的DOM2級(jí)事件處理使用了attachEvent
來實(shí)現(xiàn)脉漏,IE9以下版本只支持冒泡事件苞冯,所以attachEvent
添加的事件都是冒泡階段。attachEvent
添加的事件第一個(gè)參數(shù)是onclick
而非標(biāo)準(zhǔn)事件中的click
侧巨。使用detachEvent
實(shí)現(xiàn)刪除事件舅锄。 -
DOM3 定義方式?jīng)]變,知識(shí)新增了很多事件類型刃泡,包括UI事件巧娱,鼠標(biāo)事件,焦點(diǎn)事件烘贴,滾輪事件等等禁添。如:
element.addEventListener('keyup', function(){}, false)
因?yàn)镈OM1主要專注于HTML文檔和XML文檔,沒有涉及事件處理桨踪,所以事件處理直接從DOM0跳到DOM2老翘。
二、DOM事件模型
DOM事件模型分為兩類:一類是IE所使用的冒泡型事件(Bubbling);另一類是DOM標(biāo)準(zhǔn)定義的冒泡型與捕獲型(Capture)的事件铺峭。除IE外的其他瀏覽器都支持標(biāo)準(zhǔn)的DOM事件處理模型墓怀。
冒泡型事件處理模型(Bubbling)
如上圖所示,冒泡型事件處理模型在事件發(fā)生時(shí)卫键,首先在最精確的元素上觸發(fā)傀履,然后向上傳播,直到根節(jié)點(diǎn)莉炉。反映到DOM樹上就是事件從葉子節(jié)點(diǎn)傳播到根節(jié)點(diǎn)钓账。捕獲型事件處理模型(Captrue)
相反地,捕獲型在事件發(fā)生時(shí)首先在最頂級(jí)的元素上觸發(fā)絮宁,傳播到最低級(jí)的元素上梆暮。在DOM樹上的表現(xiàn)就是由根節(jié)點(diǎn)傳播到葉子節(jié)點(diǎn)。標(biāo)準(zhǔn)的DOM事件處理模型
標(biāo)準(zhǔn)的事件處理模型分為三個(gè)階段:
(1) 父元素中所有的捕獲型事件(如果有)自上而下地執(zhí)行
(2) 目標(biāo)元素的冒泡型事件(如果有)
(3) 父元素中所有的冒泡型事件(如果有)自下而上地執(zhí)行
三绍昂、DOM事件流
DOM標(biāo)準(zhǔn)采用捕獲+冒泡啦粹。兩種事件流都會(huì)觸發(fā)DOM的所有對(duì)象,從document對(duì)象開始窘游,也在document對(duì)象結(jié)束唠椭。
標(biāo)準(zhǔn)DOM事件流包括三個(gè)階段:事件捕獲階段,處于目標(biāo)階段和事件冒泡階段
- 事件捕獲階段:實(shí)際目標(biāo)(<div>)在捕獲階段不會(huì)接收事件张峰。也就是在捕獲階段泪蔫,事件從document到<html>再到<body>就停止了。上圖中為1~3喘批。
- 處于目標(biāo)階段:事件在<div>上發(fā)生并處理。但是事件處理會(huì)被看成是冒泡階段的一部分铣揉。
- 冒泡階段:事件又傳播回文檔饶深。
四、DOM事件捕獲的具體流程
首先接收的是window逛拱,然后是ducument敌厘,再是html標(biāo)簽(js獲取html節(jié)點(diǎn)用
document.documentElement
),然后是body朽合,最后隨著節(jié)點(diǎn)父子關(guān)系一級(jí)一級(jí)往下傳俱两,直到目標(biāo)元素。冒泡則相反曹步,從目標(biāo)元素到window一級(jí)一級(jí)往上宪彩。
通過代碼來描述事件捕獲過程:
<div id="ev" style='width:100px;height: 100px;background: blue'></div>
// 把打印順序攪亂,以免誤以為是因?yàn)閳?zhí)行順序影響
<script>
var ev = document.getElementById('ev');
ev.addEventListener('click', function (e) {
console.log('ev captrue');
}, true);
window.addEventListener('click', function (e) {
console.log('window captrue');
}, true);
document.addEventListener('click', function (e) {
console.log('document captrue');
}, true);
document.body.addEventListener('click', function (e) {
console.log('body captrue');
}, true);
document.documentElement.addEventListener('click', function (e) {
console.log('html captrue');
}, true);
// 打印結(jié)果如下:
// window captrue
// document captrue
// html captrue
// body captrue
// ev captrue
</script>
通過代碼來描述事件冒泡過程:
<div id="ev" style='width:100px;height: 100px;background: blue'></div>
// 把打印順序攪亂讲婚,以免誤以為是因?yàn)閳?zhí)行順序影響
<script>
var ev = document.getElementById('ev');
ev.addEventListener('click', function (e) {
console.log('ev captrue');
}, false);
window.addEventListener('click', function (e) {
console.log('window captrue');
}, false);
document.addEventListener('click', function (e) {
console.log('document captrue');
}, false);
document.body.addEventListener('click', function (e) {
console.log('body captrue');
}, false);
document.documentElement.addEventListener('click', function (e) {
console.log('html captrue');
}, false);
// 打印結(jié)果如下:
// ev captrue
// body captrue
// html captrue
// document captrue
// window captrue
</script>
五尿孔、Event對(duì)象的常見應(yīng)用
-
event.preventDefault()
:阻止默認(rèn)行為。常用的情況就是給一個(gè)<a>標(biāo)簽綁定了click事件,響應(yīng)函數(shù)中設(shè)置了event.preventDefault()
活合,就阻止了鏈接跳轉(zhuǎn)的行為雏婶。 -
event.stopPropagation()
:阻止冒泡行為。比如:一個(gè)父級(jí)元素綁定了一個(gè)事件白指,子元素綁定了另一個(gè)事件留晚,如果想父級(jí)元素做一件事,子元素做一件事告嘲,兩件事是分開的错维,互不影響,就需要給子元素事件中設(shè)置event.stopPropagation()
状蜗,否則子元素事件執(zhí)行時(shí)需五,按照冒泡的原則,父級(jí)元素事件也會(huì)響應(yīng)轧坎。 -
event.stopImmediatePropagation
:除了該事件的冒泡行為被阻止之外(event.stopPropagation
方法的作用)宏邮,該元素綁定的后序相同類型事件的監(jiān)聽函數(shù)的執(zhí)行也將被阻止。如一個(gè)元素上綁定了2個(gè)click事件a和b缸血,如果給a函數(shù)中添加event.stopImmediatePropagation
后蜜氨,則阻止click事件冒泡,并且阻止了b函數(shù)的執(zhí)行捎泻。 -
event.currentTarget
:當(dāng)事件遍歷DOM時(shí)飒炎,標(biāo)識(shí)事件的當(dāng)前目標(biāo)(類似于this)。如下例子:
<p>1</p>
<p>2</p>
<p>3</p>
<script>
var ps = document.getElementsByTagName('p');
for (var i = 0; i < ps.length; i++) {
ps[i].addEventListener('click', func, false);
}
function func(e) {
console.log(e.currentTarget); // 打印所點(diǎn)擊對(duì)應(yīng)的<p>節(jié)點(diǎn)
// 該函數(shù)用作事件處理器時(shí): this === e.currentTarget
}
</script>
-
event.target
:表示一個(gè)觸發(fā)事件的對(duì)象的引用笆豁,常用來實(shí)現(xiàn)事件委托郎汪。如:
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
document.getElementById("ul").addEventListener('click', function(){
console.log(event.target); // 當(dāng)點(diǎn)擊1時(shí),打印<li>1</li>
console.log(event.currentTarget); // 當(dāng)點(diǎn)擊1或2或3時(shí)闯狱,都打印整個(gè)<ul>
});
</script>
六煞赢、自定義事件
以上所講都是DOM一些自帶的事件,當(dāng)然也可以自己定義一些事件哄孤。
- ① 自定義一個(gè)事件:new Event()
- ② 給一個(gè)dom節(jié)點(diǎn)綁定自定義的事件
- ③ 使用dispatchEvent() 分派事件
<div id="ev"></div>
<script>
var ev = document.getElementById('ev');
var evt = new Event('test');
ev.addEventListener('test', function () {
console.log('test dispatch');
});
setTimeout(function () {
ev.dispatchEvent(evt);
}, 3000);
// 打開頁面3面后打印 'test dispatch'
</script>