2012-05-23 16 views
19

Hay preguntas similares, pero todas las respuestas son para intercambiar elementos html solo por el contenido interno.Cambie los elementos de 2 html y preserve los detectores de eventos en ellos

Necesito intercambiar dos divs con mucho contenido (tablas, cuadros de selección, entradas, etc.) con detectores de eventos en los elementos, etc. Sin destruir todo eso.

Tengo acceso a jQuery 1.5. Entonces las respuestas con eso están bien.

Respuesta

43

Para intercambiar dos divisores sin perder manipuladores de eventos o romper las referencias DOM, puede simplemente moverlos en el DOM. La clave es NO cambiar el innerHTML porque eso recrea nuevos nodos DOM desde cero y se pierden todos los manejadores de eventos anteriores en esos objetos DOM.

Pero, si solo mueves los elementos DOM a un lugar nuevo en el DOM, todos los eventos permanecen adjuntos porque los elementos DOM solo se vuelven a generar sin cambiar los elementos DOM.

Aquí hay una función rápida que intercambia dos elementos en el DOM. Se debe trabajar con cualquiera de los dos elementos, siempre y cuando uno no es un hijo del otro:

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

se puede ver que funcione aquí: http://jsfiddle.net/jfriend00/NThjN/


Y aquí hay una versión que funciona sin el temporal elemento insertado: demo

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

de trabajo: http://jsfiddle.net/jfriend00/oq92jqrb/

+0

Debo agregar que este código es el único que realmente funciona, excepto en dos casos de esquina: cambiar el n-primero o n-último ít. – philk

+1

@philk - No entiendo qué casos de esquina crees que no funcionan. Por favor explique. Quizás muestre un jsFiddle. – jfriend00

+0

¡Muy buen trabajo aquí! En cuanto a rendimiento, ¿qué sugieres que hagas? – Jessica

0

Esto depende en cierta medida de cómo sus eventos están vinculados a los elementos que está intercambiando. Si está utilizando jQuery, entonces la respuesta this es todo lo que necesita, realmente.

Lo principal no es delete o removeChildnode elementos, y simplemente copie y pegue el html en otro lugar. Al hacerlo, algunos navegadores borrarán todos los recursos (controladores de eventos incluidos) por lo que se perderán los eventos enlazados. Aunque IE es conocido por la pérdida de memoria cuando se trata de eventos vinculados dinámicamente. Es difícil predecir cómo se comportarán los diferentes navegadores, realmente.

Básicamente, yo diría: intercambie elementos de cualquier forma que desee, excepto para copiar/pegar cadenas de HTML, y enlazar sus eventos usando el método .live() de jQuery. Como no creo que 1.5 tenga el .on método

+0

Copiar, pegar el código HTML en otro lugar va a crear la marca nueva nodos que no tienen los mismos controladores de eventos como los nodos originales. Entonces, esto no funcionará. – jfriend00

+0

Lo sé, es por eso que dije 'intercambiar elementos de la manera que quiera, excepto para copiar/pegar cadenas de HTML'. Lo subrayé dos veces, incluso. copiar y pegar HTML es el trabajo de los demonios, IMO. Ahora que lo pienso, en este caso sugiero clonar los nodos ... –

1

Si realiza un seguimiento de los parentNodes de los dos elementos y el nextSibling de uno, puede intercambiar dos elementos con sus hijos sin ningún marcador de posición temporal.

Si el segundo elemento es hijo único o el último hijo de su elemento primario, su reemplazo se adjunta (correctamente) al padre.

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

Ésta es una función simple para el bombeo de dos elementos sin tener que volver a cargar el elemento ...

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

Nota: si el obj1 tiene un vídeo incrustado como YouTube, no se volverá a cargar cuando intercambiado. Es solo la posición de los elementos que cambiaron.

+2

muy elegante y sin la respuesta div marcador que fue más votado aquí – philk

+2

Creo en esta respuesta, 'obj2' tiene que ser después de' obj1'. Si 'obj1' fuera anterior a' obj2', no cambiarían. La respuesta @ jfriend00 intercambiará ambos elementos independientemente de si están antes o después uno del otro. – aug

+1

Esto solo funciona correctamente si los elementos están uno al lado del otro con el mismo elemento primario. Sepáralos por unos pocos elementos o dales padres diferentes y no los intercambie. Simplemente mueve uno antes que el otro. Simplemente pruebe [este jsFiddle] (http://jsfiddle.net/jfriend00/pp3op71k/) y presione el botón "Cambiar A C". – jfriend00

0

Mi función simple parece ser la más corta y más compatible. No tiene por qué marcadores de posición o volver a cargar elementos o nada desordenado así:

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

Desde jQuery está etiquetado en la pregunta, aquí es una solución de jQuery:

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

Eso es todo. jQuery lo cortará/pegará en la nueva ubicación.


Esto también podría ser útil:

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

Cuestiones relacionadas