一文詳解JavaScript的事件監(jiān)聽(最新整理)
一、認識事件處理
1.認識事件
Web頁面需要經常和用戶之間進行交互,而交互的過程中我們可能想要捕捉這個交互的過程:
- 比如
用戶點擊了某個按鈕
、用戶在輸入框里面輸入了某個文本
、用戶鼠標經過了某個位置
; - 瀏覽器需要搭建一條
JavaScript代碼和事件之間的橋梁
; - 當某個事件發(fā)生時,讓JavaScript可以
響應
(執(zhí)行某個函數(shù)),所以我們需要針對事件編寫處理程序
(handler);
如何進行事件監(jiān)聽呢?
- 事件監(jiān)聽方式一:在
script
中直接監(jiān)聽(很少使用); - 事件監(jiān)聽方式二:DOM屬性,通過元素的
on
來監(jiān)聽事件; - 事件監(jiān)聽方式三:通過EventTarget中的
addEventListener
來監(jiān)聽;
<body> <!-- 監(jiān)聽方式一 script--> <button onclick="alert('hello world');">nihao1</button> <button>nihao2</button> <button>nihao3</button> <script> // 監(jiān)聽方式二 on var btn2El = document.body.children[1]; btn2El.onclick = function () { alert("監(jiān)聽方式2"); } // 監(jiān)聽方式三 addListenEvent var btn3El = document.body.children[2]; btn3El.addEventListener("click", function () { alert("監(jiān)聽方式3"); }) </script>
2.常見的事件列表
鼠標事件:
- click —— 當鼠標點擊一個元素時(觸摸屏設備會在點擊時生成)。
- mouseover / mouseout —— 當鼠標指針移入/離開一個元素時。
- mousedown / mouseup —— 當在元素上按下/釋放鼠標按鈕時。
- mousemove —— 當鼠標移動時。
鍵盤事件:
- keydown 和 keyup —— 當按下和松開一個按鍵時。
表單(form)元素事件:
- submit —— 當訪問者提交了一個
<form>
時。 - focus —— 當訪問者聚焦于一個元素時,例如聚焦于一個
<input>
。
Document 事件:
- DOMContentLoaded —— 當 HTML 的加載和處理均完成,DOM 被完全構建完成時。
CSS 事件:
- transitionend —— 當一個 CSS 動畫完成時。
二、事件冒泡捕獲
1.認識事件流
事實上對于事件有一個概念叫做事件流,為什么會產生事件流呢?
- 我們可以想到一個問題:當我們在瀏覽器上
對著一個元素點擊時,你點擊的不僅僅是這個元素本身
; - 這是因為我們的HTML元素是存在
父子元素疊加層級
的; - 比如一個span元素是放在div元素上的,div元素是放在body元素上的,body元素是放在html元素上的;
<div class="box"> <span class="word">哈哈哈哈</span> </div>
// 認識事件流 var boxEl = document.querySelector(".box"); var wordEl = document.querySelector(".word"); boxEl.addEventListener("click", function() { console.log("boxboxbox"); }) wordEl.addEventListener("click", function () { console.log("wordwordword"); })
2.事件冒泡和事件捕獲
我們會發(fā)現(xiàn)默認情況下事件是從最內層的span向外依次傳遞的順序,這個順序我們稱之為事件冒泡
(Event Bubble);
事實上,還有另外一種監(jiān)聽事件流的方式就是從外層到內層(body -> span),這種稱之為事件捕獲
(Event Capture);
為什么會產生兩種不同的處理流呢?
- 這是因為早期瀏覽器開發(fā)時,不管是IE還是Netscape公司都發(fā)現(xiàn)了這個問題;
- 但是他們采用了
完全相反
的事件流來對事件進行了傳遞; - IE采用了事件冒泡的方式,Netscape采用了事件捕獲的方式;
那么我們如何去監(jiān)聽事件捕獲的過程呢?
3.事件捕獲和冒泡的過程
如果我們都監(jiān)聽,那么會按照如下順序來執(zhí)行:
捕獲階段
(Capturing phase):
事件(從 Window)向下走近元素。
目標階段
(Target phase):
事件到達目標元素。
冒泡階段
(Bubbling phase):
事件從元素上開始冒泡。
事實上,我們可以通過event對象來獲取當前的階段:
- eventPhase
開發(fā)中通常會使用事件冒泡
,所以事件捕獲了解即可。
// 默認情況下是事件冒泡 spanEl.addEventListener("click", function() { console.log("span元素發(fā)生了點擊~冒泡") }) divEl.addEventListener("click", function() { console.log("div元素發(fā)生了點擊~冒泡") }) bodyEl.addEventListener("click", function() { console.log("body元素發(fā)生了點擊~冒泡") }) // 設置希望監(jiān)聽事件捕獲的過程 spanEl.addEventListener("click", function() { console.log("span元素發(fā)生了點擊~捕獲") }, true) divEl.addEventListener("click", function() { console.log("div元素發(fā)生了點擊~捕獲") }, true) bodyEl.addEventListener("click", function() { console.log("body元素發(fā)生了點擊~捕獲") }, true)
三、事件對象event
1.事件對象
當一個事件發(fā)生時,就會有和這個事件相關的很多信息:
- 比如事件的
類型
是什么,你點擊的是哪一個元素
,點擊的位置
是哪里等等相關的信息; - 那么這些信息會被封裝到一個
Event對象
中,這個對象由瀏覽器創(chuàng)建
,稱之為event對象
; - 該對象給我們提供了想要的一些屬性,以及可以通過該對象進行某些操作;
如何獲取這個event對象呢?
- event對象會在傳入的事件處理(event handler)
函數(shù)回調
時,被系統(tǒng)傳入; - 我們可以在回調函數(shù)中拿到這個event對象;
這個對象中都有哪些常見的屬性和操作呢?
2.event常見的屬性和方法
常見的屬性:
- type:事件的類型;
- target:當前事件發(fā)生的元素;
- currentTarget:當前處理事件的元素;
- eventPhase:事件所處的階段;
- offsetX、offsetY:事件發(fā)生在元素內的位置;
- clientX、clientY:事件發(fā)生在客戶端內的位置;
- pageX、pageY:事件發(fā)生在客戶端相對于document的位置;
- screenX、screenY:事件發(fā)生相對于屏幕的位置;
常見的方法:
preventDefault
:取消事件的默認行為;stopPropagation
:阻止事件的進一步傳遞(冒泡或者捕獲都可以阻止);
// 認識事件流 var boxEl = document.querySelector(".box"); var wordEl = document.querySelector(".word"); // 事件冒泡 wordEl.addEventListener("click", function (event) { console.log("word冒泡", event.target, event.currentTarget); console.log(event.type);//click console.log(event.eventPhase);//2 }) wordEl.addEventListener("click", function (event) { console.log("word捕獲", event.target, event.currentTarget); console.log(event.type);//click console.log(event.eventPhase);//2 }, true) boxEl.addEventListener("click", function (event) { console.log("box捕獲", event.target, event.currentTarget); console.log(event.type);//click console.log(event.eventPhase);//1 }, true) document.body.addEventListener("click", function (event) { console.log("body捕獲", event.target, event.currentTarget); console.log(event.type);//click console.log(event.eventPhase);//1 // 停止傳遞 // event.stopPropagation(); }, true) var aEl = document.querySelector("a"); console.log(aEl); console.log(aEl.href); aEl.addEventListener("click", function (event) { console.log("a標簽冒泡"); // 阻止默認行為:比如a標簽的跳轉 event.preventDefault(); })
3.事件處理中的this
在函數(shù)中,我們也可以通過this來獲取當前的發(fā)生元素:
divEl.onclick = function(event) { console.log(this) console.log(event.currentTarget) console.log(divEl) console.log(this === divEl) }
這是因為在瀏覽器內部,調用event handler是綁定到當前的target上的
四、EventTarget使用
1.EventTarget類
我們會發(fā)現(xiàn),所有的節(jié)點、元素都繼承自EventTarget
- 事實上Window也繼承自EventTarget;
那么這個EventTarget是什么呢?
- EventTarget是一個DOM接口,主要用于
添加
、刪除
、派發(fā)
Event事件;
EventTarget常見的方法:
addEventListener
:注冊某個事件類型以及事件處理函數(shù);removeEventListener
:移除某個事件類型以及事件處理函數(shù);dispatchEvent
:派發(fā)某個事件類型到EventTarget上;
var btnEl = document.querySelector("button") // 1.將監(jiān)聽函數(shù)移除的過程 // var foo = function() { // console.log("監(jiān)聽到按鈕的點擊") // } // btnEl.addEventListener("click", foo) // // 需求: 過5s鐘后, 將這個事件監(jiān)聽移除掉 // setTimeout(function() { // btnEl.removeEventListener("click", foo) // }, 5000) // 這種做法是無法移除的 btnEl.addEventListener("click", function() { console.log("btn監(jiān)聽的處理函數(shù)~") }) setTimeout(function() { btnEl.removeEventListener("click", function() {}) }, 5000)
// 派發(fā)事件 setTimeout(() => { // 3秒后觸發(fā)點擊事件 btnEl.dispatchEvent(new Event("click")); }, 3000);
五、事件委托模式
1.事件委托
事件冒泡在某種情況下可以幫助我們實現(xiàn)強大的事件處理模式 – 事件委托模式
(也是一種設計模式)
那么這個模式是怎么樣的呢?
- 因為當
子元素被點擊
時,父元素可以通過冒泡可以監(jiān)聽到子元素的點擊
; - 并且可以通過
event.target
獲取到當前監(jiān)聽的元素;
案例:一個ul中存放多個li,點擊某一個li會變成紅色
- 方案一:監(jiān)聽每一個li的點擊,并且做出相應;
- 方案二:在ul中監(jiān)聽點擊,并且通過event.target拿到對應的li進行處理;
- 因為這種方案并不需要遍歷后給每一個li上添加事件監(jiān)聽,所以它更加高效;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> ul,li { list-style: none; margin: 0; padding: 0; } .item { display: inline-block; padding: 20px; } .active { background-color: yellow; color: blue; } </style> </head> <body> <ul> <li class="item">吃飯睡覺打豆豆</li> <li class="item">吃飯睡覺打豆豆</li> <li class="item">吃飯睡覺打豆豆</li> <li class="item">吃飯睡覺打豆豆</li> <li class="item">吃飯睡覺打豆豆</li> </ul> <script> var ulEl = document.querySelector("ul"); ulEl.addEventListener("click", function (event) { // 委托模式 // 獲取觸發(fā)事件的元素 event.target.classList.toggle("active"); }) </script> </body> </html>
2.事件委托的標記
某些事件委托可能需要對具體的子組件進行區(qū)分,這個時候我們可以使用data-*
對其進行標記:
比如多個按鈕的點擊,區(qū)分點擊了哪一個按鈕:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div class="box"> <button data-action="search">搜索~</button> <button data-action="new">新建~</button> <button data-action="remove">移除~</button> <button>1111</button> </div> <script> var boxEl = document.querySelector(".box") boxEl.onclick = function(event) { var btnEl = event.target var action = btnEl.dataset.action switch (action) { case "remove": console.log("點擊了移除按鈕") break case "new": console.log("點擊了新建按鈕") break case "search": console.log("點擊了搜索按鈕") break default: console.log("點擊了其他") } } </script> </body> </html>
六、常見的事件
1.常見的鼠標事件
接下來我們來看一下常見的鼠標事件(不僅僅是鼠標設備,也包括模擬鼠標的設備,比如手機、平板電腦)
常見的鼠標事件:
1.1 mouseover和mouseenter的區(qū)別
mouseenter和mouseleave
- 不支持冒泡
- 進入子元素依然屬于在該元素內,沒有任何反應
mouseover和mouseout
支持冒泡
- 進入元素的子元素時
- 先調用父元素的mouseout
- 再調用子元素的mouseover
- 因為支持冒泡,所以會將mouseover傳遞到父元素中;
var boxEl = document.querySelector(".box"); var containerEl = document.querySelector(".container"); // mouseenter mouseleave // containerEl.addEventListener("mouseenter", function (event) { // console.log("鼠標進來拉") // }) // containerEl.addEventListener("mouseleave", function (event) { // console.log("鼠標離開拉") // }) // mouseover mouseout containerEl.addEventListener("mouseover", function (event) { console.log("鼠標進來拉") }) containerEl.addEventListener("mouseout", function (event) { console.log("鼠標離開拉") })
2.常見的鍵盤事件
常見的鍵盤事件:
事件的執(zhí)行順序是 onkeydown、onkeypress、onkeyup
- down事件先發(fā)生;
- press發(fā)生在文本被輸入;
- up發(fā)生在文本輸入完成;
我們可以通過key和code來區(qū)分按下的鍵:
- code:“按鍵代碼”(“KeyA”,“ArrowLeft” 等),特定于鍵盤上按鍵的物理位置。
- key:字符(“A”,“a” 等),對于非字符(non-character)的按鍵,通常具有與 code 相同的值。
var inputEl = document.querySelector("input") var btnEl = document.querySelector("button") // inputEl.onkeydown = function() { // console.log("onkeydown") // } // inputEl.onkeypress = function() { // console.log("onkeypress") // } // inputEl.onkeyup = function(event) { // console.log(event.key, event.code) // } // 1.搜索功能 btnEl.onclick = function() { console.log("進行搜索功能", inputEl.value) } inputEl.onkeyup = function(event) { if (event.code === "Enter") { console.log("進行搜索功能", inputEl.value) } } // 2.按下s的時候, 搜索自動獲取焦點 document.onkeyup = function(event) { if (event.code === "KeyS") { inputEl.focus() } }
3.常見的表單事件
針對表單也有常見的事件:
var inputEl = document.querySelector("input") // 1.獲取焦點和失去焦點 // inputEl.onfocus = function() { // console.log("input獲取到了焦點") // } // inputEl.onblur = function() { // console.log("input失去到了焦點") // } // 2.內容發(fā)生改變/輸入內容 // 輸入的過程: input // 內容確定發(fā)生改變(離開): change // inputEl.oninput = function() { // console.log("input事件正在輸入內容", inputEl.value) // } // inputEl.onchange = function() { // console.log("change事件內容發(fā)生改變", inputEl.value) // } // 3.監(jiān)聽重置和提交 var formEl = document.querySelector("form") formEl.onreset = function(event) { console.log("發(fā)生了重置事件") event.preventDefault() } formEl.onsubmit = function(event) { console.log("發(fā)生了提交事件") // axios庫提交 event.preventDefault() }
4.文檔加載事件
DOMContentLoaded
:瀏覽器已完全加載 HTML,并構建了 DOM 樹,但像<img>
和樣式表之類的外部資源可能尚未加載 完成。
load
:瀏覽器不僅加載完成了 HTML,還加載完成了所有外部資源:圖片,樣式等。
// 注冊事件監(jiān)聽 window.addEventListener("DOMContentLoaded", function() { // 1.這里可以操作box, box已經加載完畢 // var boxEl = document.querySelector(".box") // boxEl.style.backgroundColor = "orange" // console.log("HTML內容加載完畢") // 2.獲取img對應的圖片的寬度和高度 var imgEl = document.querySelector("img") console.log("圖片的寬度和高度:", imgEl.offsetWidth, imgEl.offsetHeight) }) window.onload = function() { console.log("文檔中所有資源都加載完畢") // var imgEl = document.querySelector("img") // console.log("圖片的寬度和高度:", imgEl.offsetWidth, imgEl.offsetHeight) } window.onresize = function() { console.log("創(chuàng)建大小發(fā)生改變時") }
事件類型:https://developer.mozilla.org/zh-CN/docs/Web/Events
到此這篇關于JavaScript的事件監(jiān)聽的文章就介紹到這了,更多相關JavaScript的事件監(jiān)聽內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
PHPMyAdmin導入時提示文件大小超出PHP限制的解決方法
這篇文章主要介紹了PHPMyAdmin導入時提示文件大小超出PHP限制的解決方法,造成這個問題的原因是PHP上傳大小限制為2MB,修改PHP.ini配置即可解決這問題,需要的朋友可以參考下2015-03-03微信小程序使用this.setData()遇到的問題及解決方案詳解
this.setData估計是小程序中最經常用到的一個方法,但是要注意其實他是有限制的,忽略這些限制的話,會導致數(shù)據(jù)無法更新,下面這篇文章主要給大家介紹了關于微信小程序使用this.setData()遇到的問題及解決方案,需要的朋友可以參考下2022-08-08