其實好久以前就接觸過DOM事件流了,可是在很長時間沒有用到以後,就把它忘記了,因此今天特地來寫一下,順便回顧一下DOM時間流的一些知識javascript
DOM事件流是有兩種的,一種是捕獲型事件流,另一種是冒泡型事件流,二者其實都很好理解,下面咱們就來詳細介紹一下,爲了你們更好的理解,咱們就先介紹下冒泡型事件流html
在咱們討論詳細瞭解以前,咱們首先要弄理清一些知識點前端
1. event: 當前事件是什麼事件,click,onmouseover?
2. callback: 當前事件所執行的回調
3. option | useCapture: 第三個參數是比較複雜的,
有兩種狀況,當第三個參數只傳一個Boolean值時,此時就能夠打開捕獲模式,
固然第三個參數還能夠傳入一個對象,這個你們能夠去MDN上看一下,面試的時候仍是會公司問的
options: {
capture
once: 是否只執行一次當前回調
passive:表示當前監聽器永遠不會調用preventDefault函數
最後一個option的話,由於有一些兼容性,就不在這裏介紹了
}
複製代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<div>
<p>
<a href="void: javascript(0)">點我讓你看事件捕獲</a>
</p>
</div>
</body>
<script>
$('div').click(function() {
console.log(2)
})
$('p').click(function() {
console.log(1)
})
$('a').click(function() {
console.log(0)
})
</script>
</html>
複製代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<div>
<p>
<a href="void: javascript(0)">
<span>123</span>
</a>
</p>
</div>
</body>
<script>
let div = document.getElementsByTagName('div')[0]
let p = document.getElementsByTagName('p')[0]
let a = document.getElementsByTagName('a')[0]
let span = document.getElementsByTagName('span')[0]
div.addEventListener("click", function() {
console.log(2)
})
p.addEventListener("click", function() {
console.log(1)
})
a.addEventListener("click", function() {
console.log(0)
}, true)
span.addEventListener("click", function() {
console.log(-1)
})
</script>
</html>
複製代碼
事件捕獲咱們能夠經過addEventListener的第三個參數控制開關,可是事件冒泡咱們該如何阻止呢,難道任由事件冒泡出現嗎?幸運的是咱們有stopPropagation這個函數,這個函數就是用來阻止事件冒泡的(其實也能夠用來阻止事件捕獲),先上代碼java
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<div>
<p>
<a href="void: javascript(0)">
<span>123</span>
</a>
</p>
</div>
</body>
<script>
let div = document.getElementsByTagName('div')[0]
let p = document.getElementsByTagName('p')[0]
let a = document.getElementsByTagName('a')[0]
let span = document.getElementsByTagName('span')[0]
div.addEventListener("click", function() {
console.log(2)
})
p.addEventListener("click", function(e) {
e.stopPropagation()
console.log(1)
})
a.addEventListener("click", function(e) {
console.log(0)
// e.stopPropagation()
})
span.addEventListener("click", function() {
console.log(-1)
})
</script>
</html>
複製代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<div>
<p>
<a href="void: javascript(0)">
<span>123</span>
</a>
</p>
</div>
</body>
<script>
let div = document.getElementsByTagName('div')[0]
let p = document.getElementsByTagName('p')[0]
let a = document.getElementsByTagName('a')[0]
let span = document.getElementsByTagName('span')[0]
div.addEventListener("click", function() {
console.log(2)
})
p.addEventListener("click", function(e) {
e.stopPropagation()
console.log(1)
}, true)
a.addEventListener("click", function(e) {
console.log(0)
})
span.addEventListener("click", function() {
console.log(-1)
})
</script>
</html>
複製代碼
咱們能夠看到的是,控制檯的打印是隻有1的,這也就是說,這個函數不只僅是用於阻止事件冒泡,它還能夠用於阻止事件捕獲,更能夠說,事件流的三個階段它都能阻止,這就是他的做用jquery
那麼除了使用stopPropagation()以外,咱們還有其餘的方法阻止嗎,你們猜的不錯,咱們確實還有一種方法,來阻止事件流,那就是經過return false,這個方法是有一些缺陷的,他是只有在jQuery中才能生效,在原生js中只能是**阻止默認行爲(注意這個名詞,後面咱們會提到)**的,先上代碼git
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<div>
<p>
<a href="void: javascript(0)">點我讓你看事件捕獲</a>
</p>
</div>
</body>
<script>
$('div').click(function() {
console.log(2)
})
$('p').click(function() {
console.log(1)
return false
})
$('a').click(function() {
console.log(0)
})
</script>
</html>
複製代碼
上面咱們在講return false的時候,咱們提到了一個名詞,阻止默認行爲,那麼什麼是默認行爲呢,咱們舉個栗子,當咱們點擊a標籤的時候,它會自動跳轉到href對應的地址,這個跳轉就叫默認行爲,咱們能夠經過return false來阻止一些默認行爲 除此以外,還有另外一種方法就是經過調用preventDefault方法來實現,這個函數也是用來阻止默認事件的github
咱們在使用preventDefault和stopPropagation的時候,是會有兼容性的,在IE中是不存在這兩個函數的,那麼在IE中咱們是如何實現阻止冒泡和阻止默認事件的呢,看代碼面試
//阻止冒泡事件
function stopBubble(e){
if(e && e.stopPropagation){
// 非IE瀏覽器
e.stopPropagation();
}else{
//IE瀏覽器
window.event.cancelBubble=true;
}
}
// 阻止默認行爲
//阻止瀏覽器默認行爲
function stopDefault(e){
//標準瀏覽器
if(e && e.preventDefault){
e.preventDefault();
}
//個別IE
else{
window.event.returnValue=fale;
return false;
}
}
複製代碼
經過以上代碼,咱們就能夠完美的實現阻止冒泡和默認行爲了ajax
在咱們討論了這麼長的事件捕獲和事件冒泡以後,咱們要想一下,爲何會有事件捕獲和事件冒泡呢 這就是咱們接下來要討論的事件代理(事件委託),api
那麼什麼是事件委託呢,事件委託就是利用事件冒泡,只指定一個事件處理程序,就能夠管理某一類型的全部事件(--- 源自JavaScript高級程序設計),
那麼爲何會出現事件委託呢,當咱們有1個li的時候,咱們給li加上click事件,這樣是徹底沒有問題的,可是當咱們有成百上千個li呢,此時咱們會怎麼處理,固然一種最簡單的方法就是for循環遍歷,而後給每一個li都加上click事件,這樣確實能實現,可是咱們要想到的是,html頁面的渲染速度是和dom的操做的多少掛鉤的,而dom操做的多少會和綁定的事件的數量掛鉤的,綁定的數量越多,渲染確定是越慢的,那麼此時你確定會問了,有什麼好的解決方法嗎,此時咱們就能夠用到這個名詞了,事件委託,有限事件委託的原理就是事件冒泡,當咱們給li添加事件的時候,此時事件流會順着li向外層的ul流去,那麼此時咱們即可以只在ul上添加和li上相同的事件,即可以實現和在li上添加的相同的效果,咱們先上代碼看一下
html
<ul id="ul1">
<li>你好</li>
<li>你好</li>
<li>你好</li>
<li>你好</li>
<li>你好</li>
<li>你好</li>
<li>你好</li>
<li>你好</li>
</ul>
複製代碼
window.onload = function(){
var oUl = document.getElementById("ul1");
var aLi = oUl.getElementsByTagName('li');
for(var i=0;i<aLi.length;i++){
aLi[i].onclick = function(){
alert(123);
}
}
}
複製代碼
上面這種方式是給每一個li添加事件,這個毫無疑問會下降渲染速度,下面咱們看一下事件代理以後的代碼
window.onload = function(){
var oUl = document.getElementById("ul1");
oUl.onclick = function(){
alert(123);
}
}
複製代碼
咱們僅僅須要綁定一個事件,變能夠實現相同的效果,豈不是美哉?,因此這就是咱們常說的事件代理
======================================================================= 分割線,DOM事件流已經分析完畢了, 若是有什麼不正確的地方歡迎你們指出來,我是一隻在前端路上前進的程序袁,並且我會一直前進下去的,但願能和你們共同進步 歡迎你們進個人github上去看一下,個人github