2012-05-23 3 views
19

Es gibt ähnliche Fragen, aber alle Antworten sind für den Austausch von HTML-Elementen nur für den Inhalt innerhalb.Vertauschen Sie 2 HTML-Elemente und bewahren Sie Ereignis-Listener auf ihnen

Ich muss zwei divs mit viel Inhalt (Tabellen, Auswahlboxen, Eingaben usw.) mit Event-Listener auf den Elementen usw. vertauschen, ohne all das zu zerstören.

Ich habe Zugriff auf jQuery 1.5. Die Antworten damit sind in Ordnung.

Antwort

43

Um zwei divs zu vertauschen, ohne Event-Handler zu verlieren oder DOM-Referenzen zu brechen, können Sie sie einfach im DOM verschieben. Der Schlüssel besteht NICHT darin, den Befehl innerHTML zu ändern, da dadurch neue DOM-Knoten von Grund auf neu erstellt werden und alle früheren Ereignishandler für diese DOM-Objekte verloren gehen.

Wenn Sie jedoch nur die DOM-Elemente an eine neue Stelle im DOM verschieben, bleiben alle Ereignisse angehängt, da die DOM-Elemente nur neu gerendert werden, ohne die DOM-Elemente selbst zu ändern.

Hier ist eine schnelle Funktion, die zwei Elemente im DOM tauschen würde. Es sollte mit zwei Elementen arbeiten, solange man nicht ein Kind des anderen ist:

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

Sie können es hier sehen arbeiten: http://jsfiddle.net/jfriend00/NThjN/


Und hier ist eine Version, die ohne die vorübergehende funktioniert Element eingefügt:

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

Arbeits Demo: http://jsfiddle.net/jfriend00/oq92jqrb/

+0

Ich könnte hinzufügen, dass dieser Code der einzige ist, der tatsächlich funktioniert, außer für 2 Ecken Fälle: swapping die n-erste oder n-letzte Artikel. – philk

+1

@philk - Ich verstehe nicht, welche Ecke Fälle, die Sie denken, funktionieren nicht. Bitte erkläre. Vielleicht ein jsFiddle zeigen. – jfriend00

+0

Wirklich nette Arbeit hier! Leistungsmäßig, was schlagen Sie vor? – Jessica

0

Dies hängt davon ab, wie Ihre Ereignisse an die Elemente gebunden sind, die Sie austauschen. Wenn Sie jQuery verwenden, dann ist this Antwort alles, was Sie wirklich brauchen.

Die Hauptsache ist nicht delete oder removeChildnode die Elemente, und kopieren Sie einfach die HTML-Code woanders. Einige Browser löschen dabei alle Ressourcen (Event-Handler enthalten), so dass gebundene Ereignisse verloren gehen. Obwohl IE ist bekannt für das Lecken von Speicher, wenn es um dynamisch gebundene Ereignisse kommt. Es ist schwer vorherzusagen, wie sich verschiedene Browser tatsächlich verhalten werden.

Grundsätzlich würde ich sagen: Elemente beliebig austauschen, außer zum Kopieren/Einfügen von HTML-Zeichenfolgen, und binden Sie Ihre Ereignisse mit jQuery .live() Methode. Da ich glaube nicht, dass 1.5 hat die .on Methode

+0

Kopieren, Einfügen der HTML woanders brandneuen Knoten schaffen wird, die die gleichen Event-Handler wie die ursprünglichen Knoten nicht haben:


Dies auch hilfreich sein könnte. Also, das wird nicht funktionieren. – jfriend00

+0

Ich weiß, deshalb habe ich gesagt 'swap Elemente in irgendeiner Weise wie Sie wollen, außer für das Kopieren/Einfügen von HTML-Zeichenfolgen'. Ich habe das sogar zweimal betont. Kopieren-Einfügen-HTML ist die Teufel-Arbeit, IMO. Kommen Sie, um darüber nachzudenken, in diesem Fall würde ich vorschlagen, die Knoten zu klonen ... –

1

Wenn Sie die parentNodes der beiden Elemente und die nextSibling-Funktion von eins verfolgen, können Sie zwei Elemente mit ihren untergeordneten Elementen ohne temporäre Platzhalter austauschen.

Wenn das zweite Element ein einziges untergeordnetes Element oder das letzte untergeordnete Objekt des übergeordneten Elements ist, wird dessen Ersetzung (ordnungsgemäß) an das übergeordnete Element angehängt.

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

Dies ist eine einfachere Funktion zwei Elemente zum Austausch, ohne das Element tatsächlich neu geladen ...

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

Hinweis: Wenn das obj1 ein eingebettetes Video wie YouTube hat, wird es nicht neu geladen, wenn getauscht. Es ist nur die Position der Elemente, die sich geändert haben.

+2

sehr elegant und ohne den Marker div Antwort, die am meisten hier gewählt wurde – philk

+2

Ich glaube an diese Antwort, 'obj2' muss nach' obj1' sein. Wenn "obj1" vor "obj2" wäre, würden sie nicht tauschen. @ jfriend00 antwort tauscht beide Elemente aus, unabhängig davon, ob sie vor oder nacheinander stehen. – aug

+1

Dies funktioniert nur richtig, wenn Elemente mit dem gleichen Elternteil direkt nebeneinander liegen. Trennen Sie sie durch ein paar Elemente oder geben Sie ihnen verschiedene Eltern, und sie tauschen sie nicht aus. Es bewegt sich nur eins vor dem anderen. Probieren Sie einfach [diese jsFiddle] (http://jsfiddle.net/jfriend00/pp3op71k/) und drücken Sie die "Swap A C" -Taste. – jfriend00

0

Meine einfache Funktion scheint die kürzeste und am weitesten kompatible zu sein. Dabei spielt es keine Platzhalter benötigen oder Elemente oder so etwas chaotisch nachladen:

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

Da jQuery ist in der Frage markiert, hier ist ein jQuery-Lösung:

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

Das ist es. jQuery wird es an der neuen Position ausschneiden/einfügen.

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

Verwandte Themen