由點(diǎn)擊頁面其它地方隱藏div所想到的jQuery的delegate
先從最簡單的開始,假如頁面有一個(gè)id為test的div,我們要實(shí)現(xiàn)點(diǎn)擊頁面其它地方隱藏該div:
<div id="test" style="margin:100px;background-color:#3e3;width:100px;height:100px;">
</div>
對(duì)于這個(gè)問題一般有兩種思路,這兩種思路都會(huì)利用事件冒泡這一原理,想要詳細(xì)了解Javascript事件機(jī)制可以看看JavaScript與HTML交互——事件,這不是本文重點(diǎn),所以這里只是簡單介紹一下事件冒泡,
事件冒泡
IE的事件冒泡:事件開始時(shí)由最具體的元素接收,然后逐級(jí)向上傳播到較為不具體的元素
Netscape的事件捕獲:不太具體的節(jié)點(diǎn)更早接收事件,而最具體的元素最后接收事件,和事件冒泡相反
DOM事件流:DOM2級(jí)事件規(guī)定事件流包括三個(gè)階段,事件捕獲階段,處于目標(biāo)階段,事件冒泡階段,首先發(fā)生的是事件捕獲,為截取事件提供機(jī)會(huì),然后是實(shí)際目標(biāo)接收事件,最后是冒泡句階段。
Opera、Firefox、Chrome、Safari都支持DOM事件流,IE不支持事件流,只支持事件冒泡
如有以下html,點(diǎn)擊div區(qū)域,按照不同的模型事件元素的click事件觸發(fā)順序如下所示:
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Test Page</title>
</head>
<body>
<div>
Click Here</div>
</body>
</html>

在觸發(fā)DOM上的某個(gè)事件的時(shí)候會(huì)產(chǎn)生一個(gè)事件對(duì)象event,這個(gè)對(duì)象包含著所有與事件有關(guān)的信息,包括產(chǎn)生事件的元素、事件類型等相關(guān)信息。所有瀏覽都支持event對(duì)象,但支持方式不同。事件對(duì)象有一個(gè)方法(W3C:stopPropagation)/屬性(IE:cancelBulle=true)可以阻止事件繼續(xù)冒泡或捕獲。我們?nèi)绻朐谑录芭莸侥吃貢r(shí)阻止冒泡可以寫一個(gè)這樣的兼容瀏覽器方法:
function stopPropagation(e) {//把事件對(duì)象傳入
if (e.stopPropagation) //支持W3C標(biāo)準(zhǔn)
e.stopPropagation();
else //IE8及以下瀏覽器
e.cancelBubble = true;
}
因?yàn)樗械臑g覽器都支持事件冒泡,瀏覽器兼容性考慮,我們一般綁定事件的的時(shí)候都會(huì)利用事件冒泡而不是事件捕獲。了解了這個(gè)之后我們可以看看下面兩種思路了。
思路一
第一種思路分兩步
第一步:對(duì)document的click事件綁定事件處理程序,使其隱藏該div
第二步:對(duì)div的click事件綁定事件處理程序,阻止事件冒泡,防止其冒泡到document,而調(diào)用document的onclick方法隱藏了該div。
<script type="text/javascript">
function stopPropagation(e) {
if (e.stopPropagation)
e.stopPropagation();
else
e.cancelBubble = true;
}
$(document).bind('click',function(){
$('#test').css('display','none');
});
$('#test').bind('click',function(e){
stopPropagation(e);
});
</script>
這樣當(dāng)點(diǎn)擊頁面非div區(qū)域的時(shí)候,直接或?qū)訉用芭輹?huì)調(diào)用document的onclick方法,隱藏該div,而點(diǎn)擊div或其子元素的時(shí)候,事件總會(huì)冒泡的div本身,這時(shí)候會(huì)阻止事件繼續(xù)冒泡,不會(huì)調(diào)用doument的onclick方法致使div被隱藏,從而完成了我們的需求。
思路二
我們之前提到,在觸發(fā)DOM上的某個(gè)事件的時(shí)候會(huì)產(chǎn)生一個(gè)事件對(duì)象event,這個(gè)對(duì)象包含著所有與事件有關(guān)的信息,包括產(chǎn)生事件的元素、事件類型等相關(guān)信息,思路一中div的click事件處理程序傳入的參數(shù)就是這個(gè)event對(duì)象。訪問IE中的event對(duì)象有幾種不同的方式,取決于指定事件處理程序的方法。直接為DOM元素添加事件處理程序時(shí),event對(duì)象作為window對(duì)象的一個(gè)屬性存在。
event對(duì)象包含了一個(gè)重要屬性:target(W3C)/srcElement(IE),這個(gè)屬性標(biāo)識(shí)了觸發(fā)事件的原始元素,思路二就是要利用這個(gè)屬性。我們可以直接對(duì)document的click事件綁定事件處理程序,在事件處理程序中判讀事件源是否為id==test的div元素或其子元素,如果是則方法return不做操作,如果不是則隱藏該div。
<script type="text/javascript">
$(document).bind('click',function(e){
var e = e || window.event; //瀏覽器兼容性
var elem = e.target || e.srcElement;
while (elem) { //循環(huán)判斷至跟節(jié)點(diǎn),防止點(diǎn)擊的是div子元素
if (elem.id && elem.id=='test') {
return;
}
elem = elem.parentNode;
}
$('#test').css('display','none'); //點(diǎn)擊的不是div或其子元素
});
</script>
這樣當(dāng)點(diǎn)擊頁面任何地方的時(shí)候都會(huì)層層冒泡至document的click事件,事件處理程序會(huì)判斷事件源是否為id==test的div或其子元素,如果是方法return,否則隱藏該div,也能夠?qū)崿F(xiàn)我們的需求。
注意點(diǎn)及優(yōu)劣
這兩種思路都依賴于事件冒泡,所以我們?cè)谔幚砥渌嚓P(guān)元素的click事件的時(shí)候一定要注意這點(diǎn),避免其他相關(guān)元素的click事件處理程序中包含阻止事件冒泡代碼而影響了該功能。
這兩種方式都很容易理解,貌似思路一更優(yōu)秀一些,看起來它的處理更簡單一些,不用去層層判斷事件源,直接把click事件綁定在該div上。在這個(gè)例子中確實(shí)如此,但是有些復(fù)雜的頁面就不盡然了,假如我們有一個(gè)頁面,上面有數(shù)十個(gè)div都需要點(diǎn)擊頁面其它地方隱藏這類問題
<div class="dialogs">
<div class="dialog">
<div id="1">1</div>
<div id="2">2</div>
</div>
<div class="dialog">
<div id="1">1</div>
<div id="2">2</div>
</div>
<div class="dialog">
<div id="1">1</div>
<div id="2">2</div>
</div>
...
</div>
我們用思路一寫出的代碼可能是這樣:
<script type="text/javascript">
function stopPropagation(e) {
if (e.stopPropagation)
e.stopPropagation();
else
e.cancelBubble = true;
}
$(document).bind('click',function(){
$('.dialog').css('display','none');
});
$('.dialog').bind('click',function(e){
stopPropagation(e);
});
</script>
看起來簡單依舊的樣子,但是我們仔細(xì)想想就會(huì)發(fā)現(xiàn)問題,我們?cè)诿總€(gè)dialog上都綁定了類似的方法,維護(hù)如此多的click事件處理程序?qū)?nèi)存來說絕對(duì)是可開銷,導(dǎo)致我們頁面運(yùn)行緩慢。而且如果我們可以動(dòng)態(tài)使用ajax創(chuàng)建新dialog問題又來了,新創(chuàng)建的dialog不能實(shí)現(xiàn)隱藏功能!因?yàn)榻壎ê瘮?shù)已經(jīng)執(zhí)行完了,不會(huì)再為新的dialog綁定click事件處理程序,我們只能自己來做此事。也就是說思路一無法把處理程序附加到可能還未存在于DOM中的DOM元素之上。因?yàn)樗侵苯影烟幚沓绦蚪壎ǖ礁鱾€(gè)元素上,它不能把處理程序綁定到還未存在于頁面中的元素之上。
這時(shí)候就是思路二展示身手的時(shí)候了,我們看看思路二在這種時(shí)候代碼的書寫
<script type="text/javascript">
$(document).bind('click',function(e){
var e = e || window.event;
var elem = e.target || e.srcElement;
while (elem) {
if (elem.className && elem.className.indexOf('dialog')>-1) {
return;
}
elem = elem.parentNode;
}
$('#test').css('display','none');
});
</script>
改動(dòng)也相當(dāng)?shù)男。覀儊砜纯词遣皇悄芙鉀Q上邊的兩個(gè)問題了,首先無論多少個(gè)dialog我們只是綁定了一個(gè)click事件處理程序,對(duì)性能影響不大,添加一個(gè)新的dialog思路二的代碼還好不好使呢,依舊好使,這樣我們就能發(fā)現(xiàn)在復(fù)雜頁面的情況下實(shí)際上思路二是一種更優(yōu)秀的解決方案。
這些都明白了,我們就能說說本文的第二個(gè)主角jQuery的delegate方法了。
delegate
首先看看jQuery官方對(duì)delegate的語法及描述
.delegate( selector, eventType, handler(eventObject) )
Description: Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements.
delegate() 方法為指定的元素(屬于被選元素的子元素)添加一個(gè)或多個(gè)事件處理程序,并規(guī)定當(dāng)這些事件發(fā)生時(shí)運(yùn)行的函數(shù)。
使用 delegate() 方法的事件處理程序適用于當(dāng)前或未來的元素(比如由腳本創(chuàng)建的新元素)。
$( "table" ).delegate( "td", "click", function() {
$( this ).toggleClass( "chosen" );
});
通過上面語句我們就可以為所有table的td綁定click事件處理程序。
delegate方法設(shè)計(jì)意圖在于把處理程序附加到單個(gè)元素上或是一小組元素之上,監(jiān)聽后代元素上的事件而不是循環(huán)遍歷并把同一個(gè)函數(shù)逐個(gè)附加到DOM中的多個(gè)個(gè)元素上。把處理程序附加到一個(gè)(或是一小組)祖先元素上而不是直接把處理程序附加到頁面中的所有元素上,從而帶來性能上的優(yōu)化。
jQuery版隱藏dialog
通過上面知識(shí)我們可以發(fā)現(xiàn)jQuery的delegate方法可以方便實(shí)現(xiàn)我們隱藏div的需求
<script type="text/javascript">
$('.dialogs').delegate('.dialog','click',function(){
$(this).css('display','none');
});
</script>
使用jQuery我們發(fā)現(xiàn)比我們思路二在性能上又有了小幅提升,因?yàn)槲覀儾恍枰芭葜羋ocument處理了,只需要在dialog的父元素就可以處理完成了,可以不至于把很多類似功能都綁定到document上,需要注意的一點(diǎn)就是jQuery已經(jīng)貼心的幫我們把this處理為事件源,處理起來更是如魚得水了。
delegate與bind
通過上面我們說一堆我們可以在權(quán)衡使用bind還是delegate上有一定依據(jù)了,如果就單獨(dú)綁定一個(gè)元素的事件處理程序,用bind還是很合適的,但是如果處理很多類似元素的事件處理程序的時(shí)候不妨考慮一下delegate,看看是否對(duì)提高性能有所幫助。
- jquery特效 點(diǎn)擊展示與隱藏全文
- jquery實(shí)現(xiàn)點(diǎn)擊展開列表同時(shí)隱藏其他列表
- JQuery控制div外點(diǎn)擊隱藏而div內(nèi)點(diǎn)擊不會(huì)隱藏的方法
- JQuery實(shí)現(xiàn)點(diǎn)擊div以外的位置隱藏該div窗口
- Jquery實(shí)現(xiàn)點(diǎn)擊切換圖片并隱藏顯示內(nèi)容(2種方法實(shí)現(xiàn))
- 基于JQuery實(shí)現(xiàn)鼠標(biāo)點(diǎn)擊文本框顯示隱藏提示文本
- Jquery 點(diǎn)擊按鈕顯示和隱藏層的代碼
- 基于jquery鼠標(biāo)點(diǎn)擊其它地方隱藏層的實(shí)例代碼
- jquery實(shí)現(xiàn)點(diǎn)擊其他區(qū)域時(shí)隱藏下拉div和遮罩層的方法
相關(guān)文章
jquery判斷對(duì)象是否為空并遍歷對(duì)象的簡單實(shí)例
下面小編就為大家?guī)硪黄猨query判斷對(duì)象是否為空并遍歷對(duì)象的簡單實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-07-07關(guān)于HTML5的data-*自定義屬性的總結(jié)
大家總是習(xí)慣使用HTML標(biāo)簽添加自定義屬性來存儲(chǔ)和操作數(shù)據(jù),所以才在HTML5規(guī)范里增加了一個(gè)自定義data屬性,這樣使用更便捷,一起跟隨小編過來看看吧2018-05-05使用jQuery快速解決input中placeholder值在ie中無法支持的問題
本篇文章主要介紹了使用jQuery快速解決input中placeholder值在ie中無法支持的問題。需要的朋友可以過來參考下,希望對(duì)大家有所幫助2014-01-01jQuery調(diào)用AJAX時(shí)Get和post公用的亂碼解決方法實(shí)例說明
js調(diào)用AJAX時(shí)Get和post的亂碼解決辦法以前有寫過的但是使用js代碼比較繁瑣,下面與大家分享下使用jQuery該怎么解決,遇到類似情況的朋友可以參考下哈2013-06-06jQuery基于事件控制實(shí)現(xiàn)點(diǎn)擊顯示內(nèi)容下拉效果
這篇文章主要介紹了jQuery基于事件控制實(shí)現(xiàn)點(diǎn)擊顯示內(nèi)容下拉效果,涉及jQuery事件響應(yīng)及元素屬性動(dòng)態(tài)操作相關(guān)技巧,需要的朋友可以參考下2017-03-03jQuery 翻頁組件yunm.pager.js實(shí)現(xiàn)div局部刷新的思路
翻頁插件有很多種,做出來的效果都非常棒,這篇文章主要介紹了jQuery 翻頁組件yunm.pager.js實(shí)現(xiàn)div局部刷新的思路,非常不錯(cuò),需要的朋友可以參考下2016-08-08