注冊事件
給元素添加事件,稱為注冊事件或者綁定事件。
注冊事件有兩種方式:傳統方式和方法監聽注冊方式
傳統方式
on開頭的事件,例如onclick
<button onclick=“alert('hi~')”></button>
或
btn.onclick = function() {}
具有唯一性:同一個元素同一個事件只能設置一個處理函數,最后注冊的處理函數將會覆蓋前面注冊的處理函數
方法監聽注冊方式
eventTarget.addEventListener(type, listener[, useCapture])
eventTarget.addEventListener()方法將指定的監聽器注冊到 eventTarget(目標對象)上,當該對象觸發指定的事件時,就會執行事件處理函數。IE9 之前的 IE 不支持此方法,可使用 attachEvent() 代替
該方法接收三個參數:
-
type:事件類型字符串,比如 click 、mouseover ,注意這里不要帶 on
-
listener:事件處理函數,事件發生時,會調用該監聽函數
-
useCapture:是否捕獲階段,可選參數,是一個布爾值,默認是 false。下面看完DOM事件流方志。
特點:同一個元素同一個事件可以注冊多個監聽器,按注冊順序依次執行
attachEvent 事件監聽方式
eventTarget.attachEvent(eventNameWithOn, callback)
eventTarget.attachEvent()方法將指定的監聽器注冊到 eventTarget(目標對象) 上,當該對象觸發指定的事件時,指定的回調函數就會被執行。
-
eventNameWithOn:事件類型字符串,比如 onclick 、onmouseover ,這里要帶 on
-
callback: 事件處理函數,當目標觸發事件時回調函數被調用
注意:IE8 及早期版本支持
刪除事件
傳統注冊方式:eventTarget.onclick = null;
方法監聽注冊方式
eventTarget.removeEventListener(type, listener[, useCapture]);
或
eventTarget.detachEvent(eventNameWithOn, callback);
DOM事件流
事件流描述的是從頁面中接收事件的順序
事件發生時會在元素節點之間按照特定的順序傳播,這個傳播過程即 DOM 事件流。
DOM 事件流分為3個階段:
-
捕獲階段
-
當前目標階段
-
冒泡階段
- 事件冒泡: IE 最早提出,事件開始時由最具體的元素接收,然后逐級向上傳播到到 DOM 最頂層節點的過程。
- 事件捕獲: 網景最早提出,由 DOM 最頂層節點開始,然后逐級向下傳播到到最具體的元素接收的過程。
我們向水里面扔一塊石頭,首先它會有一個下降的過程,這個過程就可以理解為從最頂層向事件發生的最具體元素(目標點)的捕獲過程;之后會產生泡泡,會在最低點( 最具體元素)之后漂浮到水面上,這個過程相當於事件冒泡。
事件發生時會在元素節點之間按照特定的順序傳播,這個傳播過程即 DOM 事件流。
注意
-
JS 代碼中只能執行捕獲或者冒泡其中的一個階段。
-
onclick 和 attachEvent 只能得到冒泡階段。
-
addEventListener(type, listener[, useCapture])第三個參數如果是 true,表示在事件捕獲階段調用事件處理程序;如果是 false(不寫默認就是false),表示在事件冒泡階段調用事件處理程序。
-
實際開發中我們很少使用事件捕獲,我們更關注事件冒泡。
-
有些事件是沒有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave
-
事件冒泡有時候會帶來麻煩,有時候又會幫助很巧妙的做某些事件,后面講解。
案例
<head>
<meta charset="UTF-8">
<title>事件流</title>
<style>
.father {
overflow: hidden; /*防止嵌套盒子外邊距塌陷*/
width: 200px;
height: 200px;
background-color: #1bc4fb;
margin: 100px auto;
text-align: center;
}
.son {
width: 100px;
height: 100px;
background-color: pink;
margin: 50px;
line-height: 100px;
}
</style>
</head>
<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
let son = document.querySelector('.son');
son.addEventListener('click',function () {
alert('son')
},true)
let father = document.querySelector('.father');
father.addEventListener('click',function () {
alert('father')
},true)
</script>
</body>
如上案例,當點擊son盒子時先彈出father還是son呢?
答案是先彈出father,因為addEventListener第三個參數中設置為true,表示處於捕獲階段(document -> html -> body -> father -> son),由外向內,先觸發父盒子的事件再觸發子元素的事件
如果改為false呢?則先彈出的是son
事件對象
什么是事件對象
eventTarget.onclick = function(event) {}
或
eventTarget.addEventListener('click', function(event) {})
// 這個 event 就是事件對象,我們還喜歡的寫成 e 或者 evt
官方解釋:event 對象代表事件的狀態,比如鍵盤按鍵的狀態、鼠標的位置、鼠標按鈕的狀態。
簡單理解:事件發生后,跟事件相關的一系列信息數據的集合都放到這個對象里面,這個對象就是事件對象event,它有很多屬性和方法
比如:
-
誰綁定了這個事件。
-
鼠標觸發事件的話,會得到鼠標的相關信息,如鼠標位置。
-
鍵盤觸發事件的話,會得到鍵盤的相關信息,如按了哪個鍵。
使用
eventTarget.onclick = function(event) {
// 這個 event 就是事件對象,我們還喜歡的寫成 e 或者 evt
}
eventTarget.addEventListener('click', function(event) {
// 這個 event 就是事件對象,我們還喜歡的寫成 e 或者 evt
})
這個 event 是個形參,系統幫我們設定為事件對象,不需要傳遞實參過去。
當我們注冊事件時, event 對象就會被系統自動創建,並依次傳遞給事件監聽器(事件處理函數)。
常見屬性和方法
屬性 | 描述 | DOM |
---|---|---|
bubbles | 返回布爾值,指示事件是否是起泡事件類型。 | 2 |
cancelable | 返回布爾值,指示事件是否可擁可取消的默認動作。 | 2 |
currentTarget | 返回其事件監聽器觸發該事件的元素。 | 2 |
eventPhase | 返回事件傳播的當前階段。 | 2 |
target | 返回觸發此事件的元素(事件的目標節點)。 | 2 |
timeStamp | 返回事件生成的日期和時間。 | 2 |
type | 返回當前 Event 對象表示的事件的名稱。 | 2 |
方法 | 描述 | DOM |
---|---|---|
initEvent() | 初始化新創建的 Event 對象的屬性。 | 2 |
preventDefault() | 通知瀏覽器不要執行與事件關聯的默認動作。例如組織鏈接跳轉 | 2 |
stopPropagation() | 不再派發事件。 |
e.target 和 this 的區別:
-
this 是事件綁定的元素, 這個函數的調用者(綁定這個事件的元素)
-
e.target 是事件觸發的元素
事件對象的兼容性方案
事件對象本身的獲取存在兼容問題:
-
標准瀏覽器中是瀏覽器給方法傳遞的參數,只需要定義形參 e 就可以獲取到。
-
在 IE6~8 中,瀏覽器不會給方法傳遞參數,如果需要的話,需要到
window.event
中獲取查找。
解決: e = e || window.event;
阻止事件冒泡
事件冒泡:開始時由具體的元素接收,然后逐級向上傳播到到 DOM 最頂層節點。
事件冒泡本身的特性,會帶來壞處,也會帶來的好處,需要我們靈活掌握。
-
標准寫法:利用事件對象里面的
stopPropagation()
方法,e.stopPropagation()
-
非標准寫法:IE 6-8 利用事件對象
cancelBubble
屬性e.cancelBubble = true;
兼容性問題解決方案
if(e && e.stopPropagation){
e.stopPropagation();
}else{
window.event.cancelBubble = true;
}
事件委托
<ul>
<li>知否知否,應該有彈框在手</li>
<li>知否知否,應該有彈框在手</li>
<li>知否知否,應該有彈框在手</li>
<li>知否知否,應該有彈框在手</li>
<li>知否知否,應該有彈框在手</li>
</ul>
上例中若想實現點擊每個 li 都會彈出對話框,以前需要給每個 li 注冊事件,是非常辛苦的,而且訪問 DOM 的次數越多,就會延長整個頁面的交互就緒時間。
解決方案:事件委托
原理
當需要為多個相同子節點設置相同事件時,不再為每個子節點單獨設置,而是為其父節點設置事件監聽器,然后利用冒泡原理影響每個子節點。
以上案例:給 ul 注冊點擊事件,然后利用事件對象的 target 可以定位到當前點擊的 li,點擊 li后,事件會冒泡到 ul 上。
優點:只操作了一次 DOM ,提高了程序的性能
常用鼠標事件
屬性 | 描述 | DOM |
---|---|---|
onclick | 當用戶點擊某個對象時調用的事件句柄。 | 2 |
oncontextmenu | 在用戶點擊鼠標右鍵打開上下文菜單時觸發 | |
ondblclick | 當用戶雙擊某個對象時調用的事件句柄。 | 2 |
onmousedown | 鼠標按鈕被按下。 | 2 |
onmouseenter | 當鼠標指針移動到元素上時觸發。 | 2 |
onmouseleave | 當鼠標指針移出元素時觸發 | 2 |
onmousemove | 鼠標被移動。 | 2 |
onmouseover | 鼠標移到某元素之上。 | 2 |
onmouseout | 鼠標從某元素移開。 | 2 |
onmouseup | 鼠標按鍵被松開。 |
鼠標事件對象
屬性 | 描述 | DOM |
---|---|---|
e.altKey | 返回當事件被觸發時,"ALT" 是否被按下。 | 2 |
e.button | 返回當事件被觸發時,哪個鼠標按鈕被點擊。 | 2 |
e.clientX | 返回當事件被觸發時,鼠標指針的水平坐標。 | 2 |
e.clientY | 返回當事件被觸發時,鼠標指針的垂直坐標。 | 2 |
e.screenX | 返回當某個事件被觸發時,鼠標指針的水平坐標。 | 2 |
e.screenY | 返回當某個事件被觸發時,鼠標指針的垂直坐標。 | 2 |
e.pageX | 返回鼠標相當於文檔頁面的 X 坐標,IE9+支持 | |
e.pageY | 返回鼠標相當於文檔頁面的 Y 坐標,IE9+支持 |
案例
//禁止鼠標右鍵
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
//禁止鼠標選中
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
//圖片跟隨鼠標移動
<style>
img {
position: absolute;
}
</style>
</head>
<body>
<img src="angel.gif">
<script>
let angel = document.querySelector('img');
document.addEventListener('mousemove',function (e) {
angel.style.left = `${e.pageX}px`
angel.style.top = `${e.pageY}px`
})
</script>
</body>
① 鼠標不斷的移動,使用鼠標移動事件: mousemove
② 在頁面中移動,給document注冊事件
③ 圖片要移動距離,而且不占位置,我們使用絕對定位即可
④ 核心原理: 每次鼠標移動,我們都會獲得最新的鼠標坐標, 把這個x和y坐標做為圖片的top和left 值就可以移動圖片
常用鍵盤事件
鍵盤事件
屬性 | 描述 | DOM |
---|---|---|
onkeydown | 某個鍵盤按鍵被按下。 | 2 |
onkeypress | 某個鍵盤按鍵被按下並松開。不識別功能鍵入Ctrl、shift | 2 |
onkeyup | 某個鍵盤按鍵被松開。 | 2 |
注意:
- 如果使用addEventListener 不需要加 on
- onkeypress 和前面2個的區別是,它不識別功能鍵,比如左右箭頭,shift 等。
- 三個事件的執行順序是: keydown -- keypress --- keyup
- onkeydown 和 onkeyup 不區分字母大小寫,onkeypress 區分字母大小寫。在我們實際開發中,我們更多的使用keydown和keyup, 它能識別所有的鍵(包括功能鍵)Keypress 不識別功能鍵
鍵盤事件對象
屬性 | 描述 | DOM |
---|---|---|
keyCode | 返回onkeypress事件觸發的鍵的值的字符代碼,或者 onkeydown 或 onkeyup 事件的鍵的代碼。 |
- keyCode屬性能區分大小寫,返回不同的ASCII值