一、事件
跟用戶交互時,dom結(jié)構(gòu)發(fā)不發(fā)生改變,此時就用到事件了。
事件是當(dāng)用戶對瀏覽器進(jìn)行點擊某個地方都可能觸發(fā)任何一個事件,如用戶鼠標(biāo)單擊時、 鼠標(biāo)移動到元素上。
二、事件流
1.事件冒泡模型
事件開始時由最具體的元素接收,然后逐級向上傳播到較為不具體的元素,也就是說
從里向外

2.事件捕獲模型
從外向里

3.DOM事件流模型
先捕獲,在冒泡

三、使用方式
DOM0
事件處理程序
也稱事件偵聽器,當(dāng)用戶或瀏覽器自身執(zhí)行了某個事件,而響應(yīng)某個事件就叫事件處理程序
1.js指定事件
<input id="btnClick" type="button" value="Click Here" />
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
btnClick.onclick = function showMessage() {//元素.事件=事件處理函數(shù) () //onclick也可是其他事件名稱
alert(this.id);
};
</script>
//如果是多個相同事件注冊用這種方式,最后一個執(zhí)行,之前的被覆蓋了
(2)對一個元素綁定多個事件函數(shù) (注:會發(fā)生覆蓋)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<button id="btn">click me</button>
</body>
</html>
<script>
var btn = document.querySelector('#btn')
//#事件01
btn.onclick = function(){
console.log(this)
console.log(this.innerText)
}
//#事件02
btn.onclick = function(){
console.log('hello world')
}
</script>

DOM2事件處理程序
DOM2級事件定義了兩個方法用于處理指定和刪除事件處理程序的操作:
- addEventListener
- removeEventListener
所有的DOM節(jié)點都包含這兩個方法,并且它們都接受三個參數(shù):
1.事件類型
2.事件處理方法
3.布爾參數(shù),如果是true表示在捕獲階段調(diào)用事件處理程序,如果是false,則是在事件冒泡階段處理
綁定事件
addEventListener
為同一個元素綁定多個相同的事件:
綁定事件的兩個屬性:
- 對象.addEventListener("事件類型",事件處理函數(shù),false);--谷歌和火狐支持,IE8不支持
- 對象.attachEvent("有on的事件類型(如:onclick)",事件處理函數(shù))--谷歌不支持,火狐不支持,IE8支持
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<input type="button" value="按鈕" id="btn"/>
</body>
<script>
如:
第一種:
//為按鈕綁定點擊事件
//參數(shù)1:事件的類型----事件的名字,沒有on
//參數(shù)2:事件處理函數(shù)----函數(shù)(命名函數(shù),匿名函數(shù))
//參數(shù)3:布爾類型----默認(rèn)是事件冒泡(false),事件捕獲(true)
function btn$(id) {
return document.getElementById(id);
}
btn$("btn").addEventListener("click",function () {
console.log("呵呵");
},false);//默認(rèn)是false,可寫可不寫
btn$("btn").addEventListener("click",function () {
console.log("哈哈");
},false);
btn$("btn").addEventListener("click",function () {
console.log("哦哦");
},false);
btn$("btn").addEventListener("click",function () {
console.log("諤諤");
},false);
第二種:
//參數(shù)1:事件類型---事件名字,有on
//參數(shù)2:事件處理函數(shù)---函數(shù)(命名函數(shù),匿名函數(shù))
function btn$(id) {
return document.getElementById(id);
}
btn$("btn").attachEvent("onclick",function () {
console.log("諤諤");
});
btn$("btn").attachEvent("onclick",function () {
console.log("哦哦");
});
btn$("btn").attachEvent("onclick",function () {
console.log("哈哈");
});
//JavaScript指定事件的事件是:onclick,DOM2事件處理程序的事件是:click
</script>
沒有發(fā)生覆蓋

總結(jié):總結(jié)綁定事件的區(qū)別:
- addEventListener();
- attachEvent()
- 相同點: 都可以為元素綁定事件
- 不同點:
- 1.方法名不一樣
- 2.參數(shù)個數(shù)不一樣addEventListener三個參數(shù),attachEvent兩個參數(shù)
- 3.addEventListener 谷歌,火狐,IE11支持,IE8不支持
- attachEvent 谷歌火狐不支持,IE11不支持,IE8支持
- 4.this不同,addEventListener 中的this是當(dāng)前綁定事件的對象
- attachEvent中的this是window
- 5.addEventListener中事件的類型(事件的名字)沒有on
- attachEvent中的事件的類型(事件的名字)有on
為按鈕綁定多個點擊事件
function btn$(id) {
return document.getElementById(id);
}
btn$("btn").addEventListener("click",function () {
console.log(this);
},false);
btn$("btn").attachEvent("onclick",function () {
console.log(this);
});
如何解綁事件(一般情況下不做)
removeEventListener
removeEventListener不能使用匿名函數(shù)(無法獲知要移除誰)
如:
<script type="text/javascript">
var btnClick = document.getElementById('btnClick');
var handler=function() {
alert(this.id);
}
btnClick.removeEventListener('click', handler, false);
</script>
四、演示
冒泡階段與阻止冒泡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
<style>
#dv1{
width: 300px;
height: 200px;
border: 1px solid ;
}
#dv2{
width: 250px;
height: 150px;
border: 1px solid ;
}
#dv3{
width: 200px;
height: 100px;
border: 1px solid ;
}
</style>
</head>
<body>
<div id="dv1">a
<div id="dv2">b
<div id="dv3">c</div>
</div>
</div>
<script>
function $(id) {
return document.getElementById(id);
}
//事件冒泡-->阻止事件冒泡,
//如何阻止事件冒泡: window.event.cancelBubble=true; IE特有的,谷歌支持,火狐不支持
//.preventDefault() //取消時間默認(rèn)行為。
// .stopPropagation(); 谷歌和火狐支持。 //描述:取消事件進(jìn)一步捕獲或冒泡
$("dv1").onclick=function () {
console.log(this.id);
};
$("dv2").onclick=function () {
console.log(this.id);
//window.event.cancelBubble=true; //阻止事件冒泡
};
//事件處理參數(shù)對象
$("dv3").onclick=function (e) { //加參數(shù)e
console.log(this.id);
e.stopPropagation(); //阻止事件冒泡 //參數(shù)e
console.log();
};
</script>
</body>
</html>

- 事件冒泡:多個元素嵌套,有層次關(guān)系,這些元素都注冊了相同的事件,如果里面的元素的事件觸發(fā)了,外面的元素的該事件自動的觸發(fā)了.
整個事件就是從里到外
捕獲階段
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
<style>
#dv1 {
width: 300px;
height: 200px;
border: 1px solid ;
}
#dv2 {
width: 250px;
height: 150px;
border: 1px solid ;
}
#dv3 {
width: 200px;
height: 100px;
border: 1px solid ;
}
</style>
</head>
<body>
<div id="dv1">a
<div id="dv2">b
<div id="dv3">c</div>
</div>
</div>
<script>
function btn$(id) {
return document.getElementById(id);
}
//捕獲階段:是從里向外
//同時注冊點擊事件
var objs = [btn$("dv3"),btn$("dv2"), btn$("dv1")];
//遍歷注冊事件
objs.forEach(function (ele) {
//為每個元素綁定事件
ele.addEventListener("click", function () {
console.log(this.id);
}, true);//捕獲階段是true,冒泡階段是false
});
//該屬性在事件參數(shù)對象中存在
</script>
</body>
</html>

事件有三個階段:
* (Dom2傳播機(jī)制)三個階段:
* 1.事件捕獲階段 :從外向內(nèi)
* 2.事件目標(biāo)階段 :最開始選擇的那個
* 3.事件冒泡階段 : 從里向外
*
* 為元素綁定事件:
* addEventListener("沒有on的事件類型",事件處理函數(shù),控制事件階段的)
* 事件觸發(fā)的過程中,可能會出現(xiàn)事件冒泡的效果,為了阻止事件冒泡--->
* window.event.cancelBubble=true;谷歌,IE8支持,火狐不支持
* window.event就是一個對象,是IE中的標(biāo)準(zhǔn)
* e.stopPropagation();阻止事件冒泡---->谷歌和火狐支持
* window.event和e都是事件參數(shù)對象,一個是IE的標(biāo)準(zhǔn),一個是火狐的標(biāo)準(zhǔn)
* 事件參數(shù)e在IE8的瀏覽器中是不存在,此時用window.event來代替
* addEventListener中第三個參數(shù)是控制事件階段的
* 事件的階段有三個:
* 通過e.eventPhase這個屬性可以知道當(dāng)前的事件是什么階段的
* 如果這個屬性的值是:
* 1---->捕獲階段
* 2---->目標(biāo)階段
* 3---->冒泡
* 一般默認(rèn)都是冒泡階段,很少用捕獲階段
* 冒泡階段:從里向外
* 捕獲階段:從外向內(nèi)
區(qū)別:
onlick與addEventListener的區(qū)別?
1.onclick事件在同一時間只能指向唯一對象
2.addEventListener給一個事件注冊多個listener
3.addEventListener對任何DOM都是有效的,而onclick僅限于HTML
4.addEventListener可以控制listener的觸發(fā)階段,(捕獲/冒泡)。對于多個相同的事件處理器,不會重復(fù)觸發(fā),不需要手動使用removeEventListener清除
5.IE9使用attachEvent和detachEvent
attachEvent與addEventListener的區(qū)別
參數(shù)個數(shù)不相同:
addEventListener有三個參數(shù),attachEvent只有兩個,attachEvent添加的事件處理程序只能發(fā)生在冒泡階段,addEventListener第三個參數(shù)可以決定添加的事件處理程序是在捕獲階段還是冒泡階段處理(默認(rèn)冒泡)
第一個參數(shù)意義不同:
addEventListener第一個參數(shù)是事件類型(比如click,load),而attachEvent第一個參數(shù)指明的是事件處理函數(shù)名稱(onclick,onload)事件處理程序的作用域不相同:
addEventListener的作用域是元素本身,this是指的觸發(fā)元素;而attachEvent事件處理程序會在全局變量內(nèi)運行,this是window,所以剛才例子才會返回undefined,而不是元素id為一個事件添加多個事件處理程序時執(zhí)行順序不同:
addEventListener添加會按照添加順序執(zhí)行,而attachEvent添加多個事件處理程序時順序無規(guī)律(添加的方法少的時候大多是按添加順序的反順序執(zhí)行的,但是添加的多了就無規(guī)律了),所以添加多個的時候,不依賴執(zhí)行順序的還好,若是依賴于函數(shù)執(zhí)行順序,最好自己處理,不要指望瀏覽器。
自定義事件
var EventCenter = {
on: function(type, handler){
document.addEventListener(type, handler)
},
fire: function(type, data){
return document.dispatchEvent(new CustomEvent(type, {
detail: data
}))
}
}
EventCenter.on('hello', function(e){
console.log(e.detail)
})
EventCenter.fire('hello', '你好')