先問幾個問題,你是否能快速閃過答案?
- 自下而上(冒泡)事件怎麼寫,自上而下(捕獲)又是怎麼寫?
- 捕獲型和冒泡型同時存在,誰生效?
- jquery的on或bind是冒泡,還是捕獲?
- 冒泡能夠阻止,那捕獲能夠阻止嗎?
- stopPropagation 和 stopImmediatePropagation的區別
- Event.bubbles,Event.eventPhase
- Event.cancelable,Event.cancelBubble,event.defaultPrevented
- 常用技巧
js事件的捕獲和冒泡圖
舉個例子:
點選s2,s1分別會列印什麼?
<div id="s1">s1
<div id="s2">s2</div>
</div>
<script>
s1.addEventListener("click",function(e){
console.log("s1 冒泡事件"); },false);
s2.addEventListener("click",function(e){
console.log("s2 冒泡事件");},false);
s1.addEventListener("click",function(e){
console.log("s1 捕獲事件");},true);
s2.addEventListener("click",function(e){
console.log("s2 捕獲事件");},true);
</script>
//s1 捕獲事件
//s2 冒泡事件
//s2 捕獲事件
//s1 冒泡事件
複製程式碼
點選s2,click事件從document->html->body->s1->s2(捕獲前進)這裡在s1上發現了捕獲註冊事件,則輸出"s1 捕獲事件"到達s2,已經到達目的節點。
s2上註冊了冒泡和捕獲事件,先註冊的冒泡後註冊的捕獲,則先執行冒泡,輸出"s2 冒泡事件"
再在s2上執行後註冊的事件,即捕獲事件,輸出"s2 捕獲事件"
下面進入冒泡階段,按照s2->s1->body->html->documen(冒泡前進) 在s1上發現了冒泡事件,則輸出"s1 冒泡事件"
jQuery的on事件是冒泡
下面貼上jquery的on事件的原始碼
常用技巧
onclick -->事件冒泡,重寫onlick會覆蓋之前屬性,沒有相容性問題
ele.onclik = null; //解綁單擊事件,將onlick屬性設為null即可
複製程式碼
阻止預設事件(href=""連結,submit表單提交等)
-
return false; 阻止獨享屬性(通過on這種方式)繫結的事件的預設事件
ele.onclick = function() { …… //你的程式碼 return false; //通過返回false值阻止預設事件行為 } 複製程式碼
下面貼上jQuery的原始碼但是,在jQuery中,我們常用return false來阻止瀏覽器的預設行為,那”return false“到底做了什麼?
當你每次呼叫”return false“的時候,它實際上做了3件事情:
-
event.preventDefault();
-
event.stopPropagation();
-
停止回撥函式執行並立即返回。
這3件事中用來阻止瀏覽器繼續執行預設行為的只有preventDefault,除非你想要停止事件冒泡,否則使用return false會為你的程式碼埋下很大的隱患。
-
-
event.preventDefault( ); 阻止通過 addEventListener( ) 新增的事件的預設事件
element.addEventListener(“click”, function(e){ var event = e || window.event; …… event.preventDefault( ); //阻止預設事件 },false); 複製程式碼
-
event.returnValue = false; 阻止通過 attachEvent( ) 新增的事件的預設事件(此事件為ie瀏覽器特有)
element.attachEvent(“onclick”, function(e){ var event = e || window.event; …… event.returnValue = false; //阻止預設事件 },false); 複製程式碼
把事件繫結以及事件解綁封裝成為一個函式,相容瀏覽器,包括IE6及以上(雖然現在基本上都放棄了IE9以下了hhhh)
// 事件繫結
function addEvent(element, eType, handle, bol) {
if(element.addEventListener){ //如果支援addEventListener
element.addEventListener(eType, handle, bol);
}else if(element.attachEvent){ //如果支援attachEvent
element.attachEvent("on"+eType, handle);
}else{ //否則使用相容的onclick繫結
element["on"+eType] = handle;
}
}
// 事件解綁
function removeEvent(element, eType, handle, bol) {
if(element.addEventListener){
element.removeEventListener(eType, handle, bol);
}else if(element.attachEvent){
element.detachEvent("on"+eType, handle);
}else{
element["on"+eType] = null;
}
}
複製程式碼
事件停止傳播 stopPropagation 和 stopImmediatePropagation
// 事件傳播到 element 元素後,就不再向下傳播了
element.addEventListener('click', function (event) {
event.stopPropagation();
}, true);
// 事件冒泡到 element 元素後,就不再向上冒泡了
element.addEventListener('click', function (event) {
event.stopPropagation();
}, false);
複製程式碼
但是,stopPropagation方法只會阻止【該元素的當前事件(冒泡或者捕獲)】的傳播,不會阻止該節點的其他click事件的監聽函式。也就是說,不是徹底取消click事件,它還可以正常建立一個新的click事件。
element.addEventListener('click', function (event) {
event.stopPropagation();
console.log(1);
});
element.addEventListener('click', function(event) {
// 會觸發
console.log(2);
});
複製程式碼
如果想要徹底阻止這個事件的傳播,不再觸發後面所有click的監聽函式,可以使用stopImmediatePropagation方法。 注意:是針對該事件,比如你在click裡寫了這個方法,那【使用該方法之後】的該元素上繫結的方法將失效,但是別的mousedown,mouseover方法等還是生效的。親測過~
element.addEventListener('click', function (event) {
// 會觸發
console.log(‘改方法內的可以執行’);
event.stopImmediatePropagation();
// 會觸發
console.log(1);
});
element.addEventListener('click', function(event) {
// 不會被觸發
console.log(2);
});
// Jquery同理
$(element).click(function() {
// 不會觸發
console.log(‘jquery click’)
})
$(element).hover(function() {
// 會觸發
console.log(‘jquery click’)
})
複製程式碼
Event.bubbles,Event.eventPhase
Event.bubbles屬性返回一個布林值,表示當前事件是否會冒泡。該屬性為只讀屬性,一般用來了解 Event 例項是否可以冒泡。前面說過,除非顯式宣告,Event建構函式生成的事件,預設是不冒泡的。可以根據下面的程式碼來判斷事件是否冒泡,從而執行不同的函式。
function goInput(e) {
if (!e.bubbles) {
passItOn(e);
} else {
doOutput(e);
}
}
複製程式碼
專門查了一下不支援冒泡的事件有:
- UI事件(load, unload, scroll, resize)
- 焦點事件(blur, focus)
- 滑鼠事件(mouseleave, mouseenter)
Event.eventPhase屬性返回一個整數常量,表示事件目前所處的階段。該屬性只讀。
var phase = event.eventPhase;
複製程式碼
Event.eventPhase的返回值有四種可能。
- 0,事件目前沒有發生。
- 1,事件目前處於捕獲階段,即處於從祖先節點向目標節點的傳播過程中。
- 2,事件到達目標節點,即Event.target屬性指向的那個節點。
- 3,事件處於冒泡階段,即處於從目標節點向祖先節點的反向傳播過程中。
Event.cancelable,Event.cancelBubble,event.defaultPrevented
Event.cancelable屬性返回一個布林值,表示事件是否可以取消。該屬性為只讀屬性,一般用來了解 Event 例項的特性。
大多數瀏覽器的原生事件是可以取消的。比如,取消click事件,點選連結將無效。但是除非顯式宣告,Event建構函式生成的事件,預設是不可以取消的。
var evt = new Event('foo');
evt.cancelable // false
複製程式碼
當Event.cancelable屬性為true時,呼叫Event.preventDefault()就可以取消這個事件,阻止瀏覽器對該事件的預設行為。 注意,該方法只是取消事件對當前元素的預設影響,不會阻止事件的傳播。如果要阻止傳播,可以使用stopPropagation()或stopImmediatePropagation()方法。
function preventEvent(event) {
if (event.cancelable) {
event.preventDefault();
} else {
console.warn('This event couldn\'t be canceled.');
console.dir(event);
}
}
複製程式碼
Event.cancelBubble屬性是一個布林值,該屬性可以自行設定。如果設為true,相當於執行Event.stopPropagation(),可以阻止事件的傳播。
注意:MDN裡說該特性已經從 Web 標準中刪除,雖然一些瀏覽器目前仍然支援它,但也許會在未來的某個時間停止支援,請儘量不要使用該特性。請使用 event.stopPropagation() 方法來代替該不標準的屬性.cancelBubble-MDN
Event.defaultPrevented屬性返回一個布林值,表示該事件是否呼叫過Event.preventDefault方法。該屬性只讀。
if (event.defaultPrevented) {
console.log('該事件已經取消了');
}
複製程式碼