關於動態生成dom繫結事件失效的原因及解決和live()
在測試給動態生成的dom繫結事件的時候發現事件失效,於是就測試了一下:
1. 事件失效的原因:
(1)bind事件繫結只對dom中存在的元素有效,對於我們後來動態增加的元素是監測不到,所以繫結不了
(2)同樣,當你使用var aa = document.getElementsByTagName("動態生成的元素");來獲取動態生成的元素的時候也是獲取不到的,因為網頁只會執行一次初始化繫結,之後動態生成的dom元素也是監測不到的。
2. 解決辦法:
(1)在每一個動態生成的地方都再繫結多一次事件,比如這個部落格裡面的例子
(2)把bind改用live,因為live是實時監測的,對於新增的dom元素也是有效的(因為不斷去繫結、判斷,所以可能會影響Web效能問題)
(3)把bind改用delegate,因為delegate是實時監測的。
(4)在jquery1.7 起版本用on替代了bind()、live() 和 delegate() 方法。
3. 關於最近遇到的事件失效的原因:在原本的網頁中(程式碼可見https://github.com/UFOwl/ife/tree/master/stage02/task16),我想要獲取table裡面動態生成的刪除按鈕,幫刪除按鈕繫結刪除時間,可是刪除事件失效,因為刪除按鈕是動態生成的,初始化事件繫結的時候,獲取到的table裡面的button已經是空的,所以繫結的一直都是空元素,所以點選button按鈕的時候一直沒有反應。
4. 最後的解決辦法:
注意:在這裡注意兩個問題:
(1)table裡面的元素是已經新增進入table裡面了的,所以點選那個button的時候,e.target獲取到的就是button
(2)為什麼已經將button這些元素新增進入table裡面,可是還是沒能獲取到呢,因為是init()這個函式初始化的時候獲取table裡面的button,可是此時還未進行任何操作,所以獲取到的就是空,所以沒繫結任何元素。
上面需要注意的兩個問題要分清楚,這個是問題的關鍵。
5.關於bind:每次繫結事件之後事件會一直繫結著,除非用unbind解綁之後再重新繫結,要不然事件會一直存在,所以這就是為什麼在做專案的時候,有時候ajax請求的結果會出現1,2,4,8這樣疊加,是因為如果用了bind,每次觸發事件都會繫結一次操作,所以觸發第一次的時候,ajax請求一次;第二次的時候,ajax請求1+1=2次;第三次就是1+2+1=4次;第四次就是1+2+4+1=8次,以此類推。所以如果利用bind繫結事件的話,要先unbind解綁元素原本有的事件再繫結事件,才不會導致ajax請求多次。
以上這篇關於動態生成dom繫結事件失效的原因及解決方法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援。
live()
函式用於為指定元素的一個或多個事件繫結事件處理函式。
此外,你還可以額外傳遞給事件處理函式一些所需的資料。
即使是執行live()
函式之後新新增的元素,只要它匹配當前jQuery物件的選擇器,繫結的事件處理函式仍然對其有效。
此外,可以為同一元素、同一事件型別繫結多個事件處理函式。觸發事件時,jQuery會按照繫結的先後順序依次執行繫結的事件處理函式。
要刪除通過live()
繫結的事件,請使用die()函式。
從jQuery 1.7開始,該函式被標記為已過時;從jQuery 1.9開始被移除。請使用on()函式來替代。即使在1.7版本之前,也強烈不推薦使用該函式。如果能夠不使用該函式,就不要使用。
該函式屬於jQuery
物件(例項)。
語法
jQuery 1.3 新增該函式,從jQuery 1.7開始被標記為已過時,在jQuery 1.9中被移除。其主要有以下兩種形式的用法:
用法一:jQuery 1.4 新增支援引數data
。
jQueryObject.live( events [, data ], handler )
用法二:jQuery 1.4.3 新增支援該用法。
jQueryObject.live( eventsMap )
引數
引數 | 描述 |
---|---|
events | String型別一個或多個用空格分隔的事件型別和可選的名稱空間,例如"click"、"focus click"、"keydown.myPlugin"。 |
data | 可選/任意型別觸發事件時,需要通過event.data傳遞給事件處理函式的任意資料。 |
handler | Functilive型別指定的事件處理函式。 |
eventsMap | Object型別一個Object物件,其每個屬性對應事件型別和可選的名稱空間(引數events ),屬性值對應繫結的事件處理函式(引數handler )。 |
關於引數events
中可選的名稱空間(1.4.3+才支援),請參考最下面的示例程式碼。
引數handler
中的this
指向當前DOM元素。live()
還會為handler
傳入一個引數:表示當前事件的Event物件。
引數handler
的返回值與DOM原生事件的處理函式返回值作用一致。例如"submit"(表單提交)事件的事件處理函式返回false
,可以阻止表單的提交。
如果事件處理函式handler
僅僅只用於返回false
值,可以直接將handler
設為false
。
返回值
live()
函式的返回值為jQuery型別,返回當前jQuery物件本身。
重要說明:
live()
函式並不是直接在當前jQuery物件匹配的每個元素上繫結事件處理函式,而是將事件處理函式"委託"給document
物件來處理。由於DOM 2級的事件流機制,當事件觸發時,該事件會在事件冒泡中傳遞給其所有的祖輩元素,一直傳遞到document
物件為止。當事件流傳遞到document
時,jQuery會判斷當前匹配元素是否符合觸發條件,如果該元素符合當前jQuery物件的選擇器,jQuery就會捕獲該事件,從而執行繫結的事件處理函式。
使用live()
函式需要注意以下問題:
- 當前jQuery物件必須通過選擇器字串構造,否則無法處理觸發的事件。
- 在呼叫該函式之前,jQuery會嘗試查詢當前jQuery選擇器所匹配的元素。在大文件中這可能比較耗時。
- 該函式不支援方法鏈。例如:
$("a").find(".foo").live(...)
是無效的,且無法按照預期正常工作。 - 由於
live()
的事件處理函式全部附加到document
物件上,因此在事件被處理之前,事件可能要經過最長最慢的事件路徑。 - 在由於平臺或事件差異,有些事件不支援冒泡,從而無法冒泡傳遞到
document
,此時可能無法處理該事件。 - 由於
live()
函式的事件處理函式全部附加在document
物件上,如果通過某些方式解除了document
物件上的事件繫結,可能會波及到使用live()
函式委託繫結的其他元素的事件處理函式。例如$(document).off()
。
示例&說明
以點選事件("click")為例,以下是jQuery中事件函式的常規用法(某些函式也存在其它形式的用法,此處暫不列出):
// 這裡的選擇器selector用於指定可以觸發事件的元素// 這裡的選擇器ancestor應是selector的祖輩元素,selector觸發的事件可以被其祖輩元素在事件流中捕獲,從而以"代理"的形式觸發事件。// jQuery 1.0+ (1.4.3+支援引數data) $("selector").click([ data ,] handler );// jQuery 1.0+ (1.4.3+支援引數data) $("selector").bind("click"[, data ], handler );// jQuery 1.3+ (1.4+支援引數data) $("selector").live("click"[, data ], handler );// jQuery 1.4.2+ $("ancestor").delegate("selector","click"[, data ], handler );// jQuery 1.7+ $("ancestor").on("click","selector"[, data ], handler );
請參考下面這段初始HTML程式碼:
<divid="n1"><pid="n2"><span>CodePlayer</span></p><pid="n3"><span>專注於程式設計開發技術分享</span></p><emid="n4">http://www.365mini.com</em></div><pid="n5">Google</p>
我們為<div>中的所有<p>元素繫結點選事件:
//為div中的所有p元素的click事件繫結事件處理函式//只有n2、n3可以觸發該事件 $("div p").live("click",function(){// 這裡的this指向觸發點選事件的p元素(Element) alert( $(this).text());});
執行程式碼(以下其他程式碼請自行復制到演示頁面執行)
此外,我們還可以同時繫結多個事件,併為事件處理函式傳遞一些附加的資料,我們可以通過jQuery為事件處理函式傳入的引數event
(Event事件物件)來進行處理:
var obj ={ id:5, name:"王五"};//為n5繫結mouseenter mouseleave兩個事件,併為其傳入附加資料obj// 附加資料可以是任意型別 $("#n5").live("mouseenter mouseleave", obj,function(event){var $me = $(this);var obj = event.data;// 這就是傳入的附加資料if( event.type =="mouseenter"){ $me.html("你好,"+ obj.name +"!");}elseif(event.type =="mouseleave"){ $me.html("再見,"+ obj.name +"!");}});
此外,即使符合條件的元素是live()
函式執行後新新增,繫結事件對其依然有效。同樣以初始HTML程式碼為例,我們可以編寫如下jQuery程式碼:
//為div中的所有p元素的click事件繫結事件處理函式//只有n2、n3可以觸發該事件 $("div p").live("click",function(event){ alert( $(this).text());});//後新增的n6也可以觸發上述click事件,因為它也是div中的p元素 $("#n1").append('<p id="n6">上述繫結的click事件對此元素也生效!</p>');
引數events
還支援為事件型別附加額外的名稱空間。當為同一元素繫結多個相同型別的事件處理函式時。使用名稱空間,可以在觸發事件、移除事件時限定觸發或移除的範圍。
function clickHandler(event){ alert("觸發時的名稱空間:["+ event.namespace +"]");}var $p = $("p");// A:為所有p元素繫結click事件,定義在foo和bar兩個名稱空間下 $p.live("click.foo.bar", clickHandler );// B:為所有p元素繫結click事件,定義在test名稱空間下 $p.live("click.test", clickHandler );var $n2 = $("#n2");// 觸發所有click事件 $n2.trigger("click");// 觸發A和B (event.namespace = "")// 觸發定義在foo名稱空間下的click事件 $n2.trigger("click.foo");// 觸發A (event.namespace = "foo")// 觸發定義在bar名稱空間下的click事件 $n2.trigger("click.bar");// 觸發A (event.namespace = "bar")// 觸發同時定義在foo和bar兩個名稱空間下的click事件 $n2.trigger("click.foo.bar");// 觸發A (event.namespace = "bar.foo")// 觸發定義在test名稱空間下的click事件 $n2.trigger("click.test");// 觸發B (event.namespace = "test")
live()
函式的引數eventsMap
是一個物件,可以"屬性-值"的方式指定多個"事件型別-處理函式"。對應的示例程式碼如下:
var eventsMap ={"mouseenter":function(event){ $(this).html("你好!");},"mouseleave":function(event){ $(this).html("再見!");}};//為n5繫結mouseenter mouseleave兩個事件 $("#n5").live( eventsMap );