2012-05-23 33 views
19

也有類似的問題,但所有的答案都是針對html內容進行交換的。交換2個html元素並保留它們上的事件監聽器

我需要用很多內容(表格,選擇框,輸入等)與元素等事件監聽器交換兩個div。不破壞所有這些。

我有權訪問jQuery 1.5。所以答案是可以的。

回答

43

要交換兩個div而不丟失事件處理程序或打破DOM引用,您可以將它們移動到DOM中。關鍵不是更改innerHTML,因爲它重新創建了新的DOM節點,並且這些DOM對象上的所有事件處理程序都丟失了。

但是,如果您只是將DOM元素移動到DOM中的新位置,則所有事件都會保持連接狀態,因爲DOM元素僅在不更改DOM元素本身的情況下重新進行重新設置。

這是一個快速的函數,可以交換DOM中的兩個元素。它應該與任何兩個元素工作,只要一個不是其他的孩子:

function swapElements(obj1, obj2) { 
    // create marker element and insert it where obj1 is 
    var temp = document.createElement("div"); 
    obj1.parentNode.insertBefore(temp, obj1); 

    // move obj1 to right before obj2 
    obj2.parentNode.insertBefore(obj1, obj2); 

    // move obj2 to right before where obj1 used to be 
    temp.parentNode.insertBefore(obj2, temp); 

    // remove temporary marker node 
    temp.parentNode.removeChild(temp); 
} 

你可以看到它在這裏工作:http://jsfiddle.net/jfriend00/NThjN/


而這裏的,如果沒有臨時工程版本元素插入:

function swapElements(obj1, obj2) { 
    // save the location of obj2 
    var parent2 = obj2.parentNode; 
    var next2 = obj2.nextSibling; 
    // special case for obj1 is the next sibling of obj2 
    if (next2 === obj1) { 
     // just put obj1 before obj2 
     parent2.insertBefore(obj1, obj2); 
    } else { 
     // insert obj2 right before obj1 
     obj1.parentNode.insertBefore(obj2, obj1); 

     // now insert obj1 where obj2 was 
     if (next2) { 
      // if there was an element after obj2, then insert obj1 right before that 
      parent2.insertBefore(obj1, next2); 
     } else { 
      // otherwise, just append as last child 
      parent2.appendChild(obj1); 
     } 
    } 
} 

工作演示:http://jsfiddle.net/jfriend00/oq92jqrb/

+0

我可能會補充說,除了2個角落案例外,這個代碼是唯一實際工作的代碼:交換n首或n最後項目。 – philk

+1

@philk - 我不明白你認爲哪些角落案件無效。請解釋。也許展示一個jsFiddle。 – jfriend00

+0

這裏真的很棒!在性能方面,你建議做什麼? – Jessica

0

這在某種程度上取決於您的事件如何綁定到要交換的元素。如果你使用jQuery,那麼this的答案就是你所需要的,真的。

最主要的不是deleteremoveChildnode的元素,而只是將html複製粘貼到其他地方。這樣做時,一些瀏覽器將清除所有資源(包括事件處理程序),綁定的事件將會丟失。儘管IE在動態綁定事件方面因內存泄漏而臭名昭着。真的很難預測各種瀏覽器的行爲。

基本上,我會說:以任何你喜歡的方式交換元素,除了複製/粘貼HTML字符串,並使用jQuery的.live()方法綁定事件。因爲我不認爲1.5有.on方法

+0

複製,粘貼HTML別的地方將創造全新的節點不具有相同的事件處理程序的原始節點。所以,這是行不通的。 – jfriend00

+0

我知道,這就是爲什麼我說'以任何你喜歡的方式交換元素,除了複製/粘貼HTML字符串。我甚至兩次強調這一點。複製粘貼HTML是惡魔的工作,國際海事組織。想想看,在這種情況下,我會建議克隆節點... –

1

如果跟蹤兩個元素的父節點和下一個元素的兄弟節點,則可以將兩個元素與其子元素交換而不需要任何臨時佔位符。

如果第二個元素是唯一的子元素或其父元素的最後一個子元素,則將其替換(正確)添加到父元素中。

function swap(a, b){ 
    var p1= a.parentNode, p2= b.parentNode, sib= b.nextSibling; 
    if(sib=== a) sib= sib.nextSibling; 
    p1.replaceChild(b, a); 
    if(sib) p2.insertBefore(a, sib); 
    else p2.appendChild(a); 
    return true; 
} 
8

這是交換兩個元素,而無需實際重新加載元素的簡單功能...

function swapElements(obj1, obj2) { 
    obj2.nextSibling === obj1 
    ? obj1.parentNode.insertBefore(obj2, obj1.nextSibling) 
    : obj1.parentNode.insertBefore(obj2, obj1); 
} 

注:如果OBJ1有一個嵌入式的視頻,如YouTube,換的時候也不會重新加載。 這只是變化的元素的位置。

+2

非常優雅,沒有在這裏投票最多的標記div回答 – philk

+2

我相信在這個答案中,'obj2'必須在'obj1'之後。如果'obj1'在'obj2'之前,它們不會交換。無論是之前還是之後,@ jfriend00答案都會交換這兩個元素。 – aug

+1

只有當元素彼此相鄰且父母相同時,這才能正常工作。分開幾個元素或給他們不同的父母,它不交換它們。它只是先移動一個。試試[這個jsFiddle](http://jsfiddle.net/jfriend00/pp3op71k/)並按下「Swap A C」按鈕。 – jfriend00

0

我的簡單功能似乎是最短和最廣泛的兼容。它並不需要佔位符或重載元件或任何凌亂的那樣:

function swapElements(el1, el2) { 
    var p2 = el2.parentNode, n2 = el2.nextSibling 
    if (n2 === el1) return p2.insertBefore(el1, el2) 
    el1.parentNode.insertBefore(el2, el1); 
    p2.insertBefore(el1, n2); 
} 
0

由於jQuery是在標籤的問題,這裏是一個jQuery的解決方案:

$('#el_to_move').appendTo('#target_parent_el'); 

就是這樣。 jQuery將剪切/粘貼到新位置。


這也可能是有益的:

https://api.jquery.com/detach/