一、事件的IE兼容性
在老版的IE瀏覽器中,
不支持:addEventListener和removeEventListener 兩種事件綁定的方法
支持(可實(shí)現(xiàn)):attachEvent和detachEvent 兩種方法,同時(shí)接收兩個(gè)相同參數(shù)
a、事件處理程序名稱
b、事件處理程序方法
由于IE支持事件冒泡,所以添加的程序會(huì)被添加到冒泡階段,使用attachEvent可以添加事件處理程序:
<input id="btnClick" type="button" value="Click Here" />
<script>
var btnClick = document.getElementById('btnClick')
var handler = function(){
alert(this.id)
}
btnClick.attachEvent('onclick',handler);
</script>
- attachEvent只能在冒泡階段監(jiān)聽(tīng)事件,只有兩個(gè)參數(shù):(事件類型,事件處理函數(shù))
- ie中的this:它所得到的并不是當(dāng)前元素,而是window對(duì)象,返回值則為undefined
二、跨瀏覽器的事件處理程序
了解不同的瀏覽器下處理事件處理程序的區(qū)別
在添加事件處理程序事addEventListener和attachEvent主要有幾個(gè)區(qū)別:
1、參數(shù)個(gè)數(shù)不相同,這個(gè)最直觀,addEventListener有三個(gè)參數(shù),attachEvent只有兩個(gè),attachEvent添加的事件處理程序只能發(fā)生在冒泡階段,addEventListener第三個(gè)參數(shù)可以決定添加的事件處理程序是在捕獲階段還是冒泡階段處理(我們一般為了瀏覽器兼容性都設(shè)置為冒泡階段)
2、第一個(gè)參數(shù)意義不同,addEventListener第一個(gè)參數(shù)是事件類型(比如click,load),而attachEvent第一個(gè)參數(shù)指明的是事件處理函數(shù)名稱(onclick,onload)
3、事件處理程序的作用域不相同,addEventListener的作用域是元素本身,this是指的觸發(fā)元素,而attachEvent事件處理程序會(huì)在全局變量?jī)?nèi)運(yùn)行,this是window,所以剛才例子才會(huì)返回undefined,而不是元素id
4、為一個(gè)事件添加多個(gè)事件處理程序時(shí),執(zhí)行順序不同,addEventListener添加會(huì)按照添加順序執(zhí)行,而attachEvent添加多個(gè)事件處理程序時(shí)順序無(wú)規(guī)律(添加的方法少的時(shí)候大多是按添加順序的反順序執(zhí)行的,但是添加的多了就無(wú)規(guī)律了),所以添加多個(gè)的時(shí)候,不依賴執(zhí)行順序的還好,若是依賴于函數(shù)執(zhí)行順序,最好自己處理,不要指望瀏覽器
三、事件對(duì)象
如剛才例子http://js.jirengu.com/hahid/1/edit?html,js 中在控制臺(tái)上打印出事件,事件內(nèi)都是一些對(duì)象(帶有屬性和值),可以從這堆屬性中觀察到一些重要的參考(只是部分例舉),如:
altKey:false //表示在點(diǎn)擊事件的時(shí)候,沒(méi)有點(diǎn)alt鍵
bubbles:true //表示這個(gè)事件是冒泡
clientX:39
clientY:18 //表示它的一個(gè)位置
toElement:button#btn //說(shuō)明當(dāng)前傳遞的元素
介紹幾個(gè)常用屬性:
- stopPropagation()
如圖:
[圖片上傳失敗...(image-187d5b-1534131542419)]
阻止冒泡繼續(xù)?
在dom事件流中,分別會(huì)在捕獲和冒泡階段都綁定事件,先捕獲后冒泡進(jìn)行輸出。假設(shè)我們現(xiàn)在不管捕獲,只管冒泡,并給body綁定一個(gè)監(jiān)聽(tīng)事件,當(dāng)它聽(tīng)到事件做了一件事:一點(diǎn)stopPropagation()就停止冒泡,即點(diǎn)擊div之后,body監(jiān)聽(tīng)到消息,后面的頁(yè)面元素渲染就不再處理。即將事件冒泡停止,不會(huì)再上傳消息。捕獲也亦然。
- preventDefault()
瀏覽器的默認(rèn)事件如何阻止?
某些元素?fù)碛心J(rèn)事件,為瀏覽器的默認(rèn)行為。如a鏈接點(diǎn)擊時(shí)則會(huì)跳轉(zhuǎn)、如form表單中table=submit,當(dāng)點(diǎn)擊該按鈕時(shí),瀏覽器會(huì)把它所在的form表單做一次提交。假設(shè)想阻止其默認(rèn)行為,則可以通過(guò)綁定事件:preventDefault()阻止其行為。之后再做一些校驗(yàn)或判斷,用JS 做當(dāng)前頁(yè)面跳轉(zhuǎn)。即在跳轉(zhuǎn)這一層級(jí)可以做些事:
假設(shè)制定一個(gè)域名的a鏈接才能跳轉(zhuǎn)(而頁(yè)面則是用戶可自行寫(xiě)鏈接)先阻止其默認(rèn)時(shí)間,再獲取當(dāng)前herf的值、hostname(域名)
假設(shè)表單提交,用戶校驗(yàn),校驗(yàn)成功之后,就手動(dòng)去做一些跳轉(zhuǎn)
- e.stopPropagation( ) 取消事件進(jìn)一步捕獲或冒泡
事件冒泡和事件捕獲的應(yīng)用場(chǎng)景
//選中元素
var container = document.querySelector('.container')
var box = document.querySelector('.box')
var target = document.querySelector('.target')
//綁定事件
container.addEventListener('click', function(e){
console.log('container 捕獲 click...')
},true)
box.addEventListener('click', function(e){
console.log('box 捕獲 click...')
},true)
target.addEventListener('click',function(e){
console.log('target 捕獲 click...')
},true)
container.addEventListener('click', function(e){
console.log('container 冒泡 click...')
},false)
box.addEventListener('click', function(e){
e.stopPropagation()
console.log('box 冒泡 click...')
},false)
target.addEventListener('click',function(e){
console.log('target 冒泡 click...')
},false)
如圖:
多個(gè)阻止函數(shù)來(lái)阻止冒泡事件
- e.preventDefault( ) 阻止事件默認(rèn)行為
鏈接:阻止事件默認(rèn)行為
剛開(kāi)始是這樣的:沒(méi)有跳轉(zhuǎn),只有一直輸出:
image
代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>阻止默認(rèn)事件</title>
</head>
<body>
<a >baidu</a>
</body>
</html>
<script>
document.querySelector('a').onclick = function(e){
e.preventDefault()
console.log(this.href)
}
</script>
接著看圖所示,添加一個(gè)if判斷,再點(diǎn)擊baidu鏈接,控制臺(tái)只輸出一次地址,頁(yè)面則出現(xiàn)百度的網(wǎng)頁(yè):
代碼:
//html同上
<script>
document.querySelector('a').onclick = function(e){
e.preventDefault()
console.log(this.href)
if(/baidu.com/.test(this.href)){
location.href = this.href
}
}//函數(shù)表示:如果這個(gè)鏈接是baidu.com,那就跳轉(zhuǎn)
</script>
假如html代碼中
<a >baidu</a>
改為:
<a >baidu</a>
最后頁(yè)面和控制臺(tái)都不會(huì)有任何反應(yīng)。而這就是e.preventDefault( ) 阻止事件默認(rèn)行為
四、常用HTML事件及演示
例子鏈接:常見(jiàn)事件使用演示
五、事件代理
鏈接:事件代理的一些嘗試
首先,我們?yōu)閮蓚€(gè)box綁定兩個(gè)事件,先綁定box1,如圖:
通過(guò)選擇參數(shù)$('.box')作為box1的當(dāng)前元素,所以再去綁定事件之后,則只會(huì)出現(xiàn)第一個(gè)box1文本內(nèi)容。
但是,我們嘗試地使用函數(shù)$$(selector)綁定兩個(gè)元素的事件,再點(diǎn)擊box1和box2沒(méi)有任何輸出,如圖:
通過(guò)頁(yè)面控制臺(tái)檢驗(yàn):
$$('.box')
--> NodeList(2) [div.box, div.box]//1、確實(shí)出現(xiàn)了所選的兩個(gè)元素,但是要確認(rèn)有沒(méi)有onclick
0: div.box
1: div.box
length: 2
__proto__: NodeList //3、我們所看到NodeList,是一個(gè)類數(shù)組對(duì)象,里面的屬性值并沒(méi)有onclick和addEventListener
$$('.box').onclick //2、于是測(cè)試之后undefined,即綁定事件只能針對(duì)單個(gè)去綁定事件
--> undefined
那如何解決兩個(gè)元素同時(shí)綁定事件呢?還是從控制臺(tái)nodelist的對(duì)象中尋找可用的參數(shù)去解決,即有forEach遍歷兩個(gè)元素,實(shí)現(xiàn)兩個(gè)都綁定了事件,即:
//html同上
<script>
function $$(selector){
return document.querySelectorAll(selector)
}
$$('.box').forEach(function(node){
node.onclick = function(){
console.log(this.innerText)
}
})
</script>
圖:
那么,我們有沒(méi)有更簡(jiǎn)單的方法實(shí)現(xiàn)當(dāng)前所有元素都綁定了事件?看html即可以知道,我們可以直接綁定父元素container,即
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div class="container">
<div class="box">box1</div>
<div class="box">box2</div>
<div class="hello">hello</div>
</div>
</body>
</html>
<script>
function $(selector){
return document.querySelector(selector)
}
function $$(selector){
return document.querySelectorAll(selector)
}
$('.container').onclick = function(e){
if(e.target.classList.contains('box')){
console.log(e.target.innerText)
}
}//表示:如果我點(diǎn)擊了一個(gè)元素(e.target),它的classList包含了'box',
//那么它就輸出這個(gè)元素的文本內(nèi)容。具有語(yǔ)義化
</script>
再想到更多的場(chǎng)景,如有一個(gè)按鈕,如何綁定這個(gè)按鈕實(shí)現(xiàn)這樣一個(gè)需求:當(dāng)點(diǎn)擊這個(gè)按鈕的時(shí)候,則會(huì)在父元素下再添加一個(gè)box。這個(gè)如何實(shí)現(xiàn)?如圖:
代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div class="container">
<div class="box">box1</div>
<div class="box">box2</div>
<div class="box">box3</div>
<div class="hello">hello</div>
</div>
<button id="add">add</button>
<!--需求:當(dāng)點(diǎn)擊這個(gè)按鈕的時(shí)候,則會(huì)在父元素下再添加一個(gè)box-->
</body>
</html>
<script>
function $(selector){
return document.querySelector(selector)
}
function $$(selector){
return document.querySelectorAll(selector)
}
$('.container').onclick = function(e){
if(e.target.classList.contains('box')){
console.log(e.target.innerText)
}
}//事件代理的核心所在
//表示:如果我點(diǎn)擊了一個(gè)元素(e.target),它的classList包含了'box',那么它就輸出這個(gè)元素的文本內(nèi)容。具有語(yǔ)義化
var i=4 //這是因?yàn)橹坝衎ox3了
$('#add').onclick = function(){
var box = document.createElement('div')//創(chuàng)建一個(gè)box元素
box.classList.add('box')//創(chuàng)建的當(dāng)前元素去添加一個(gè)class叫做box
box.innerText ='box' + (i++)//表示每點(diǎn)擊一次i就增加一個(gè)
$('.container').appendChild(box)//最后將box這個(gè)元素添加進(jìn).container里面
}
</script>