1. 程式人生 > >關於動態生成dom繫結事件失效的原因及解決和live()

關於動態生成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. 最後的解決辦法:

先獲取table,然後再繫結table的click事件(因為table是在原本已經存在的dom元素),然後當點選事件觸發的時候再捕獲事件的target(比如點選table裡面的button,這個時候因為已經動態生成button並append進去table裡面了,所以button是存在的,此時target指的是button),然後再進行相應的操作。

注意:在這裡注意兩個問題:

(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 );