事件
- 含義
JavaScript和HTML的交互是通過(guò)事件實(shí)現(xiàn)的崇堵。JavaScript采用異步事件驅(qū)動(dòng)編程模型,當(dāng)文檔客燕、瀏覽器鸳劳、元素或與之相關(guān)對(duì)象發(fā)生特定事情時(shí),瀏覽器會(huì)產(chǎn)生事件也搓。 - 事件類型
- 當(dāng)用戶點(diǎn)擊鼠標(biāo)時(shí)
- 當(dāng)網(wǎng)頁(yè)已加載時(shí)
- 當(dāng)圖像已加載時(shí)
- 當(dāng)鼠標(biāo)移動(dòng)到元素上時(shí)
- 當(dāng)用戶觸發(fā)按鍵時(shí)
- .....
事件流
事件流描述的是從頁(yè)面中接收事件的順序赏廓。
-
事件冒泡:事件開(kāi)始時(shí)由最具體的元素接收,然后逐級(jí)向上傳播到較為不具體的元素还绘。
-
事件捕獲:不太具體的節(jié)點(diǎn)更早接收事件楚昭,而最具體的元素最后接收事件,和事件冒泡相反拍顷。
-
DOM事件流:DOM2級(jí)事件規(guī)定事件流包括三個(gè)階段抚太,事件捕獲階段,處于目標(biāo)階段昔案,事件冒泡階段尿贫,首先發(fā)生的是事件捕獲,為截取事件提供機(jī)會(huì)踏揣,然后是實(shí)際目標(biāo)接收事件庆亡,最后是冒泡階段。
圖上:123處于事件捕獲階段捞稿,4處于目標(biāo)階段又谋,4567處于事件冒泡階段拼缝。
DOM2級(jí)事件規(guī)范明確要求捕獲階段不會(huì)涉及時(shí)間目標(biāo),但I(xiàn)E9彰亥、Safari咧七、Firefox、Opera9.5及更高版本都會(huì)在捕獲階段觸發(fā)事件對(duì)象上的事件任斋。
事件處理程序(綁定事件)
- HTML內(nèi)聯(lián)方式
<input type = 'button" value = "Click me" onclick = "alert('clicked')">
事件處理程序中的代碼在執(zhí)行時(shí)继阻,有權(quán)訪問(wèn)全局作用域中的任何代碼。
- 缺點(diǎn):
a: 存在時(shí)差問(wèn)題废酷,因?yàn)橛脩艨赡軙?huì)在HTML元素一出現(xiàn)在頁(yè)面上就觸發(fā)相應(yīng)的事件瘟檩,但當(dāng)時(shí)的事件處理程序有可能不具備執(zhí)行條件;
b: 擴(kuò)展事件處理程序的作用域鏈在不同的瀏覽器中會(huì)導(dǎo)致不同的結(jié)果澈蟆;
c: HTML與JavaScript代碼緊密耦合墨辛。
- JavaScript指定事件處理程序
- DOM0級(jí)事件
- 將一個(gè)函數(shù)值賦值給一個(gè)事件處理程序?qū)傩浴J褂肈OM0級(jí)方法指定的事件處理程序被認(rèn)為是元素的方法趴俘,所以處理程序是在元素的作用域中運(yùn)行背蟆。
var btn = document.getElementById('btn')
btn.onclick = function(){
console.log(this)//指觸發(fā)元素btn
}
- 刪除DOM0級(jí)事件處理程序的方法:
btn.onclik = null;
對(duì)象屬性重復(fù)賦值會(huì)覆蓋原先的值,所以只能綁定一個(gè)事件哮幢。
- DOM2級(jí)事件
- DOM2級(jí)事件具有兩個(gè)方法:
addEventListener()
和removeEventListener()
带膀。這兩個(gè)方法接收同樣的三個(gè)參數(shù):要處理的事件名、作為事件處理程序的函數(shù)和一個(gè)布爾值橙垢。其中垛叨,布爾值為true
表示在捕獲階段調(diào)用事件處理程序,布爾值為false
表示在冒泡階段調(diào)用事件處理程序柜某。默認(rèn)值false
嗽元。因?yàn)楹瘮?shù)可以重復(fù)執(zhí)行,所以可以添加許多事件監(jiān)聽(tīng)喂击。
var btn = document.getElementById('btn')
btn.addEventListener('click',function(){
console.log(this)
},false)
btn.addEventListener('click',function(){
console.log('hello')
},false)
執(zhí)行順序與添加事件處理程序的順序一致剂癌。
DOM2級(jí)事件的作用域是元素的作用域,所以this指代觸發(fā)元素翰绊。
- 刪除DOM2級(jí)事件處理程序:
removeEventListener()
與addEventListener()
參數(shù)要完全一致佩谷,所以事件處理程序函數(shù)為匿名函數(shù)的時(shí)候,則無(wú)法刪除监嗜。
var btn = document.getElementById('btn')
btn.addEventListener('click',function(){
console.log(this)
},false)
//下面的刪除函數(shù)無(wú)法刪除
var btn = document.getElementById('btn')
btn.removeEventListener('click',function(){
console.log(this)
},false)
//解決辦法
var handler = function(){console.log(this)}
var btn = document.getElementById('btn')
btn.addEventListener('click',handler,false)
btn.removeEventListener('click',handler,false)
- 關(guān)于this和事件
<body>
<div class = "box">
<button>click me</button>
</div>
<script>
var box = document.querySelector('.box')
var button = document.querySelector('button')
//事件可以作為參數(shù)傳遞進(jìn)來(lái)
button.addEventListener('click',function(e){
console.log(this)//監(jiān)聽(tīng)事件的元素
console.log(this.innerText)
console.log(e)//事件其實(shí)是一個(gè)對(duì)象
console.log(e.target)//事件的觸發(fā)元素btn(真正觸發(fā)事件的元素)
})
box.addEventListener('click',function(e){
console.log(this)//代表監(jiān)聽(tīng)事件的元素
console.log(this.innerText)
console.log(e)//事件其實(shí)是一個(gè)對(duì)象
console.log(e.target)//事件的觸發(fā)元素btn(真正觸發(fā)事件的元素)
</script>
</body>
- IE兼容事件
- IE事件處理程序具有兩個(gè)方法:
attachEvent()
和detachEvent()
谐檀。具有兩個(gè)完全相同的參數(shù):事件處理程序名稱和事件處理程序函數(shù)。此事件處理程序是在全局作用域下運(yùn)行的裁奇,所以this指代window
桐猬。可以添加多個(gè)事件處理程序刽肠。
var btn = document.getElementById('btn')
btn.attachEvent('onclick',function(){
console.log(this) // window
})
btn.attachEvent('onclick',function(){
console.log('hell')
})
事件處理程序的執(zhí)行順序是事件處理程序添加順序的反順序溃肪。
- 刪除事件處理程序
btn.attachEvent('onclick',handler)
btn.detachEvent('onclick',handler)
addEventListener()和attachEvent()的區(qū)別:
- 參數(shù)個(gè)數(shù)不同:
addEventListene
r有三個(gè)參數(shù)免胃,attachEvent
只有兩個(gè),attachEvent
添加的事件處理程序只能發(fā)生在冒泡階段惫撰,addEventListener
第三個(gè)參數(shù)可以決定添加的事件處理程序是在捕獲階段還是冒泡階段處理(我們一般為了瀏覽器兼容性都設(shè)置為冒泡階段)杜秸。
2.第一個(gè)參數(shù)含義不同:addEventListener
第一個(gè)參數(shù)是事件類型(比如click,load
)润绎,而attachEvent
第一個(gè)參數(shù)指明的是事件處理函數(shù)名稱(onclick,onload
)诞挨。 - 事件處理程序的作用域不同:
addEventListener
的作用域是元素本身莉撇,this
是指的觸發(fā)元素,而attachEvent
事件處理程序會(huì)在全局變量?jī)?nèi)運(yùn)行惶傻,this
是window
棍郎。· - 為一個(gè)事件添加多個(gè)事件處理程序時(shí)银室,執(zhí)行順序不同:
addEventListener
添加會(huì)按照添加順序執(zhí)行涂佃,而attachEvent
添加多個(gè)事件處理程序時(shí)順序無(wú)規(guī)律(添加的方法少的時(shí)候大多是按添加順序的反順序執(zhí)行的,但是添加的多了就無(wú)規(guī)律了)蜈敢,所以添加多個(gè)的時(shí)候辜荠,不依賴執(zhí)行順序的還好,若是依賴于函數(shù)執(zhí)行順序抓狭,最好自己處理伯病,不要指望瀏覽器。
this否过、target午笛、currentTarget的區(qū)別:
DOM0級(jí)事件和DOM2級(jí)事件,作用是元素作用域苗桂,this指代的是觸發(fā)事件的元素药磺。IE事件處理程序,作用域是全局作用域煤伟,this
指代的是window
癌佩。currentTarget
代表其事件處理程序當(dāng)前正在處理的事件的那個(gè)元素。對(duì)象this
始終等于currentTarget
便锨。而target
則只包含事件的實(shí)際目標(biāo)驼卖。
<div id = "ct">
<button id = "btn">click me</button>
</div>
<script>
var btn = document.getElementById('btn')
btn.addEventListener('click',function(){
console.log(this)
},false)
//this = target = currentTarget = btn
var div = document.getElementById('ct')
div.addEventListener('click',function(){
console.log(this)
},false)
// this = current = <div>...</div>
// target = btn
</script>
事件可以作為參數(shù)傳遞進(jìn)來(lái)
<button>click me</button>
<script>
var button = document.querySelector('button')
button.addEventListener('click',function(e){
console.log(e)//e事件其實(shí)是一個(gè)對(duì)象
})
</script>
此截圖為部分截圖
事件的封裝(兼容所有的瀏覽器)
- 封裝方法一:(不好,不建議采納)
//函數(shù)的封裝鸿秆,使其在IE瀏覽器下也能運(yùn)行(瀏覽器的兼容)
function addEvent(node,type,handler){
//元素不存在酌畜,直接退出
if(!node) return false;
//非IE下運(yùn)行
if(node.addEventListener){
node.addEventListener(type,handler,false);
return true;
}
//IE下運(yùn)行
if(node.attachEvent){
node.attachEvent('on' + type,handler,);
return true
}
return true
}
var node = document.getElementsByClassName('.box')[0]
addEvent(node,'click',function(e){
console.log(e)
console.log(this)//在IE下,this代表的是window卿叽,所以采用此種封裝不好
})
- 更好的封裝方法
<script>
function addEvent(node,type,handler) {
if(!node) return false;
if(node.addEventListener) {
node.addEventListener(type,handler,false)
return true
}
else if(node.attachEvent) {
node['e' + type + handler] = handler
node[type + handler] = function(){
node['e' + type + handler](window.event)
}
// 此處的作用是在全局作用域中桥胞,this也可以指觸發(fā)元素而不是window
//此種寫(xiě)法也可以把事件作為參數(shù)e傳遞進(jìn)來(lái)
node.attachEvent('on' + type,node[type + handler])
return true
}
else {
node['on' + type] = handler
}
}
var node = document.getElementsByClassName('.box')[0]
addEvent(node,'click',function(e){
console.log(e)
console.log(e.target)
console.log(this)
})
</script>
- 代碼解析
node['eclickfunction(){xxx}'] = function(e){
console.log(e)
console.log(this)
}
node['clickfunction(){xxx}'] = function(){
node['eclickfunction(){xxx}'](window.event)
}