一文詳解JavaScript的事件監(jiān)聽(最新整理)
一、認(rèn)識(shí)事件處理
1.認(rèn)識(shí)事件
Web頁(yè)面需要經(jīng)常和用戶之間進(jìn)行交互,而交互的過(guò)程中我們可能想要捕捉這個(gè)交互的過(guò)程:
- 比如
用戶點(diǎn)擊了某個(gè)按鈕、用戶在輸入框里面輸入了某個(gè)文本、用戶鼠標(biāo)經(jīng)過(guò)了某個(gè)位置; - 瀏覽器需要搭建一條
JavaScript代碼和事件之間的橋梁; - 當(dāng)某個(gè)事件發(fā)生時(shí),讓JavaScript可以
響應(yīng)(執(zhí)行某個(gè)函數(shù)),所以我們需要針對(duì)事件編寫處理程序(handler);
如何進(jìn)行事件監(jiān)聽呢?
- 事件監(jiān)聽方式一:在
script中直接監(jiān)聽(很少使用); - 事件監(jiān)聽方式二:DOM屬性,通過(guò)元素的
on來(lái)監(jiān)聽事件; - 事件監(jiān)聽方式三:通過(guò)EventTarget中的
addEventListener來(lái)監(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.常見的事件列表
鼠標(biāo)事件:
- click —— 當(dāng)鼠標(biāo)點(diǎn)擊一個(gè)元素時(shí)(觸摸屏設(shè)備會(huì)在點(diǎn)擊時(shí)生成)。
- mouseover / mouseout —— 當(dāng)鼠標(biāo)指針移入/離開一個(gè)元素時(shí)。
- mousedown / mouseup —— 當(dāng)在元素上按下/釋放鼠標(biāo)按鈕時(shí)。
- mousemove —— 當(dāng)鼠標(biāo)移動(dòng)時(shí)。
鍵盤事件:
- keydown 和 keyup —— 當(dāng)按下和松開一個(gè)按鍵時(shí)。
表單(form)元素事件:
- submit —— 當(dāng)訪問(wèn)者提交了一個(gè)
<form>時(shí)。 - focus —— 當(dāng)訪問(wèn)者聚焦于一個(gè)元素時(shí),例如聚焦于一個(gè)
<input>。
Document 事件:
- DOMContentLoaded —— 當(dāng) HTML 的加載和處理均完成,DOM 被完全構(gòu)建完成時(shí)。
CSS 事件:
- transitionend —— 當(dāng)一個(gè) CSS 動(dòng)畫完成時(shí)。
二、事件冒泡捕獲
1.認(rèn)識(shí)事件流
事實(shí)上對(duì)于事件有一個(gè)概念叫做事件流,為什么會(huì)產(chǎn)生事件流呢?
- 我們可以想到一個(gè)問(wèn)題:當(dāng)我們?cè)跒g覽器上
對(duì)著一個(gè)元素點(diǎn)擊時(shí),你點(diǎn)擊的不僅僅是這個(gè)元素本身; - 這是因?yàn)槲覀兊腍TML元素是存在
父子元素疊加層級(jí)的; - 比如一個(gè)span元素是放在div元素上的,div元素是放在body元素上的,body元素是放在html元素上的;
<div class="box">
<span class="word">哈哈哈哈</span>
</div>// 認(rèn)識(shí)事件流
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.事件冒泡和事件捕獲
我們會(huì)發(fā)現(xiàn)默認(rèn)情況下事件是從最內(nèi)層的span向外依次傳遞的順序,這個(gè)順序我們稱之為事件冒泡(Event Bubble);
事實(shí)上,還有另外一種監(jiān)聽事件流的方式就是從外層到內(nèi)層(body -> span),這種稱之為事件捕獲(Event Capture);
為什么會(huì)產(chǎn)生兩種不同的處理流呢?
- 這是因?yàn)樵缙跒g覽器開發(fā)時(shí),不管是IE還是Netscape公司都發(fā)現(xiàn)了這個(gè)問(wèn)題;
- 但是他們采用了
完全相反的事件流來(lái)對(duì)事件進(jìn)行了傳遞; - IE采用了事件冒泡的方式,Netscape采用了事件捕獲的方式;
那么我們?nèi)绾稳ケO(jiān)聽事件捕獲的過(guò)程呢?

3.事件捕獲和冒泡的過(guò)程
如果我們都監(jiān)聽,那么會(huì)按照如下順序來(lái)執(zhí)行:
捕獲階段(Capturing phase):
事件(從 Window)向下走近元素。
目標(biāo)階段(Target phase):
事件到達(dá)目標(biāo)元素。
冒泡階段(Bubbling phase):
事件從元素上開始冒泡。
事實(shí)上,我們可以通過(guò)event對(duì)象來(lái)獲取當(dāng)前的階段:
- eventPhase
開發(fā)中通常會(huì)使用事件冒泡,所以事件捕獲了解即可。

// 默認(rèn)情況下是事件冒泡
spanEl.addEventListener("click", function() {
console.log("span元素發(fā)生了點(diǎn)擊~冒泡")
})
divEl.addEventListener("click", function() {
console.log("div元素發(fā)生了點(diǎn)擊~冒泡")
})
bodyEl.addEventListener("click", function() {
console.log("body元素發(fā)生了點(diǎn)擊~冒泡")
})
// 設(shè)置希望監(jiān)聽事件捕獲的過(guò)程
spanEl.addEventListener("click", function() {
console.log("span元素發(fā)生了點(diǎn)擊~捕獲")
}, true)
divEl.addEventListener("click", function() {
console.log("div元素發(fā)生了點(diǎn)擊~捕獲")
}, true)
bodyEl.addEventListener("click", function() {
console.log("body元素發(fā)生了點(diǎn)擊~捕獲")
}, true)三、事件對(duì)象event
1.事件對(duì)象
當(dāng)一個(gè)事件發(fā)生時(shí),就會(huì)有和這個(gè)事件相關(guān)的很多信息:
- 比如事件的
類型是什么,你點(diǎn)擊的是哪一個(gè)元素,點(diǎn)擊的位置是哪里等等相關(guān)的信息; - 那么這些信息會(huì)被封裝到一個(gè)
Event對(duì)象中,這個(gè)對(duì)象由瀏覽器創(chuàng)建,稱之為event對(duì)象; - 該對(duì)象給我們提供了想要的一些屬性,以及可以通過(guò)該對(duì)象進(jìn)行某些操作;
如何獲取這個(gè)event對(duì)象呢?
- event對(duì)象會(huì)在傳入的事件處理(event handler)
函數(shù)回調(diào)時(shí),被系統(tǒng)傳入; - 我們可以在回調(diào)函數(shù)中拿到這個(gè)event對(duì)象;
這個(gè)對(duì)象中都有哪些常見的屬性和操作呢?
2.event常見的屬性和方法
常見的屬性:
- type:事件的類型;
- target:當(dāng)前事件發(fā)生的元素;
- currentTarget:當(dāng)前處理事件的元素;
- eventPhase:事件所處的階段;
- offsetX、offsetY:事件發(fā)生在元素內(nèi)的位置;
- clientX、clientY:事件發(fā)生在客戶端內(nèi)的位置;
- pageX、pageY:事件發(fā)生在客戶端相對(duì)于document的位置;
- screenX、screenY:事件發(fā)生相對(duì)于屏幕的位置;
常見的方法:
preventDefault:取消事件的默認(rèn)行為;stopPropagation:阻止事件的進(jìn)一步傳遞(冒泡或者捕獲都可以阻止);
// 認(rèn)識(shí)事件流
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標(biāo)簽冒泡");
// 阻止默認(rèn)行為:比如a標(biāo)簽的跳轉(zhuǎn)
event.preventDefault();
})3.事件處理中的this
在函數(shù)中,我們也可以通過(guò)this來(lái)獲取當(dāng)前的發(fā)生元素:
divEl.onclick = function(event) {
console.log(this)
console.log(event.currentTarget)
console.log(divEl)
console.log(this === divEl)
}這是因?yàn)樵跒g覽器內(nèi)部,調(diào)用event handler是綁定到當(dāng)前的target上的
四、EventTarget使用
1.EventTarget類
我們會(huì)發(fā)現(xiàn),所有的節(jié)點(diǎn)、元素都繼承自EventTarget
- 事實(shí)上Window也繼承自EventTarget;
那么這個(gè)EventTarget是什么呢?
- EventTarget是一個(gè)DOM接口,主要用于
添加、刪除、派發(fā)Event事件;
EventTarget常見的方法:
addEventListener:注冊(cè)某個(gè)事件類型以及事件處理函數(shù);removeEventListener:移除某個(gè)事件類型以及事件處理函數(shù);dispatchEvent:派發(fā)某個(gè)事件類型到EventTarget上;
var btnEl = document.querySelector("button")
// 1.將監(jiān)聽函數(shù)移除的過(guò)程
// var foo = function() {
// console.log("監(jiān)聽到按鈕的點(diǎn)擊")
// }
// btnEl.addEventListener("click", foo)
// // 需求: 過(guò)5s鐘后, 將這個(gè)事件監(jiān)聽移除掉
// setTimeout(function() {
// btnEl.removeEventListener("click", foo)
// }, 5000)
// 這種做法是無(wú)法移除的
btnEl.addEventListener("click", function() {
console.log("btn監(jiān)聽的處理函數(shù)~")
})
setTimeout(function() {
btnEl.removeEventListener("click", function() {})
}, 5000)// 派發(fā)事件
setTimeout(() => {
// 3秒后觸發(fā)點(diǎn)擊事件
btnEl.dispatchEvent(new Event("click"));
}, 3000);五、事件委托模式
1.事件委托
事件冒泡在某種情況下可以幫助我們實(shí)現(xiàn)強(qiáng)大的事件處理模式 – 事件委托模式(也是一種設(shè)計(jì)模式)
那么這個(gè)模式是怎么樣的呢?
- 因?yàn)楫?dāng)
子元素被點(diǎn)擊時(shí),父元素可以通過(guò)冒泡可以監(jiān)聽到子元素的點(diǎn)擊; - 并且可以通過(guò)
event.target獲取到當(dāng)前監(jiān)聽的元素;
案例:一個(gè)ul中存放多個(gè)li,點(diǎn)擊某一個(gè)li會(huì)變成紅色
- 方案一:監(jiān)聽每一個(gè)li的點(diǎn)擊,并且做出相應(yīng);
- 方案二:在ul中監(jiān)聽點(diǎn)擊,并且通過(guò)event.target拿到對(duì)應(yīng)的li進(jìn)行處理;
- 因?yàn)檫@種方案并不需要遍歷后給每一個(gè)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">吃飯睡覺(jué)打豆豆</li>
<li class="item">吃飯睡覺(jué)打豆豆</li>
<li class="item">吃飯睡覺(jué)打豆豆</li>
<li class="item">吃飯睡覺(jué)打豆豆</li>
<li class="item">吃飯睡覺(jué)打豆豆</li>
</ul>
<script>
var ulEl = document.querySelector("ul");
ulEl.addEventListener("click", function (event) {
// 委托模式
// 獲取觸發(fā)事件的元素
event.target.classList.toggle("active");
})
</script>
</body>
</html>2.事件委托的標(biāo)記
某些事件委托可能需要對(duì)具體的子組件進(jìn)行區(qū)分,這個(gè)時(shí)候我們可以使用data-*對(duì)其進(jìn)行標(biāo)記:
比如多個(gè)按鈕的點(diǎn)擊,區(qū)分點(diǎn)擊了哪一個(gè)按鈕:
<!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("點(diǎn)擊了移除按鈕")
break
case "new":
console.log("點(diǎn)擊了新建按鈕")
break
case "search":
console.log("點(diǎn)擊了搜索按鈕")
break
default:
console.log("點(diǎn)擊了其他")
}
}
</script>
</body>
</html>六、常見的事件
1.常見的鼠標(biāo)事件
接下來(lái)我們來(lái)看一下常見的鼠標(biāo)事件(不僅僅是鼠標(biāo)設(shè)備,也包括模擬鼠標(biāo)的設(shè)備,比如手機(jī)、平板電腦)
常見的鼠標(biāo)事件:

1.1 mouseover和mouseenter的區(qū)別
mouseenter和mouseleave
- 不支持冒泡
- 進(jìn)入子元素依然屬于在該元素內(nèi),沒(méi)有任何反應(yīng)
mouseover和mouseout
支持冒泡- 進(jìn)入元素的子元素時(shí)
- 先調(diào)用父元素的mouseout
- 再調(diào)用子元素的mouseover
- 因?yàn)橹С置芭荩詴?huì)將mouseover傳遞到父元素中;
var boxEl = document.querySelector(".box");
var containerEl = document.querySelector(".container");
// mouseenter mouseleave
// containerEl.addEventListener("mouseenter", function (event) {
// console.log("鼠標(biāo)進(jìn)來(lái)拉")
// })
// containerEl.addEventListener("mouseleave", function (event) {
// console.log("鼠標(biāo)離開拉")
// })
// mouseover mouseout
containerEl.addEventListener("mouseover", function (event) {
console.log("鼠標(biāo)進(jìn)來(lái)拉")
})
containerEl.addEventListener("mouseout", function (event) {
console.log("鼠標(biāo)離開拉")
})2.常見的鍵盤事件
常見的鍵盤事件:

事件的執(zhí)行順序是 onkeydown、onkeypress、onkeyup
- down事件先發(fā)生;
- press發(fā)生在文本被輸入;
- up發(fā)生在文本輸入完成;
我們可以通過(guò)key和code來(lái)區(qū)分按下的鍵:
- code:“按鍵代碼”(“KeyA”,“ArrowLeft” 等),特定于鍵盤上按鍵的物理位置。
- key:字符(“A”,“a” 等),對(duì)于非字符(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("進(jìn)行搜索功能", inputEl.value)
}
inputEl.onkeyup = function(event) {
if (event.code === "Enter") {
console.log("進(jìn)行搜索功能", inputEl.value)
}
}
// 2.按下s的時(shí)候, 搜索自動(dòng)獲取焦點(diǎn)
document.onkeyup = function(event) {
if (event.code === "KeyS") {
inputEl.focus()
}
}3.常見的表單事件
針對(duì)表單也有常見的事件:

var inputEl = document.querySelector("input")
// 1.獲取焦點(diǎn)和失去焦點(diǎn)
// inputEl.onfocus = function() {
// console.log("input獲取到了焦點(diǎn)")
// }
// inputEl.onblur = function() {
// console.log("input失去到了焦點(diǎn)")
// }
// 2.內(nèi)容發(fā)生改變/輸入內(nèi)容
// 輸入的過(guò)程: input
// 內(nèi)容確定發(fā)生改變(離開): change
// inputEl.oninput = function() {
// console.log("input事件正在輸入內(nèi)容", inputEl.value)
// }
// inputEl.onchange = function() {
// console.log("change事件內(nèi)容發(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庫(kù)提交
event.preventDefault()
}4.文檔加載事件
DOMContentLoaded:瀏覽器已完全加載 HTML,并構(gòu)建了 DOM 樹,但像<img> 和樣式表之類的外部資源可能尚未加載 完成。
load:瀏覽器不僅加載完成了 HTML,還加載完成了所有外部資源:圖片,樣式等。
// 注冊(cè)事件監(jiān)聽
window.addEventListener("DOMContentLoaded", function() {
// 1.這里可以操作box, box已經(jīng)加載完畢
// var boxEl = document.querySelector(".box")
// boxEl.style.backgroundColor = "orange"
// console.log("HTML內(nèi)容加載完畢")
// 2.獲取img對(duì)應(yīng)的圖片的寬度和高度
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ā)生改變時(shí)")
}事件類型:https://developer.mozilla.org/zh-CN/docs/Web/Events
到此這篇關(guān)于JavaScript的事件監(jiān)聽的文章就介紹到這了,更多相關(guān)JavaScript的事件監(jiān)聽內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- javascript如何刪除所有事件監(jiān)聽器
- JavaScript鼠標(biāo)拖動(dòng)事件監(jiān)聽使用方法以及實(shí)例效果演示
- 關(guān)于js中removeEventListener取消事件監(jiān)聽的坑
- vue.js綁定事件監(jiān)聽器示例【基于v-on事件綁定】
- vue.js過(guò)濾器+ajax實(shí)現(xiàn)事件監(jiān)聽及后臺(tái)php數(shù)據(jù)交互實(shí)例
- vuejs2.0實(shí)現(xiàn)分頁(yè)組件使用$emit進(jìn)行事件監(jiān)聽數(shù)據(jù)傳遞的方法
- javascript 組合按鍵事件監(jiān)聽實(shí)現(xiàn)代碼
相關(guān)文章
JS精準(zhǔn)判斷一個(gè)對(duì)象是不是數(shù)組的方法
這篇文章主要介紹了JavaScript中判斷數(shù)組的方法,包括Array.isArray()、instanceof、Object.prototype.toString三種方法的優(yōu)缺點(diǎn),并給出了一些使用技巧和避坑指南,其中array.isArray()是最推薦使用的方法,準(zhǔn)確可靠,跨上下文安全,是最安全、易讀的選擇2026-05-05
JS字符串統(tǒng)計(jì)操作示例【遍歷,截取,輸出,計(jì)算】
這篇文章主要介紹了JS字符串統(tǒng)計(jì)操作,結(jié)合實(shí)例形式分析了javascript字符串的遍歷,截取,輸出,計(jì)算等相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2017-03-03
JS實(shí)現(xiàn)的新浪微博大廳文字內(nèi)容滾動(dòng)效果代碼
這篇文章主要介紹了JS實(shí)現(xiàn)的新浪微博大廳文字內(nèi)容滾動(dòng)效果代碼,可實(shí)現(xiàn)頁(yè)面圖文元素定時(shí)滾動(dòng)的效果,涉及JavaScript時(shí)間函數(shù)定時(shí)改變頁(yè)面元素的相關(guān)技巧,需要的朋友可以參考下2015-11-11
JS中Promise.all 與 Promise.race的區(qū)別小結(jié)
本文主要介紹了JS中Promise.all 與 Promise.race的區(qū)別小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2026-02-02
微信小程序?qū)崿F(xiàn)組件頂端固定或底端固定效果(不隨滾動(dòng)而滾動(dòng))
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)組件頂端固定或底端固定效果(不隨滾動(dòng)而滾動(dòng)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04

