jQuery / Método / .clone() - Copiar elementos seleccionados
En jQuery, .clone() crea un nuevo objeto jQuery con copias de los elementos seleccionados, sus descendientes y texto. Clonar no los añade a la página: insértalos con .appendTo(), por ejemplo. Los eventos y datos jQuery se excluyen por defecto y se controlan con argumentos separados.
Estructura, movimiento y opciones de eventos
En la documentación de .clone(), una copia estructural profunda incluye los hijos. No garantiza independencia completa de eventos, objetos .data() y valores anidados. El segundo argumento deepWithDataAndEvents controla eventos/datos de descendientes, no la copia de los hijos DOM.
| Expresión | Elemento y descendientes | Eventos/datos de raíz | Eventos/datos de descendientes |
|---|---|---|---|
| .clone() | Copiados | No copiados | No copiados |
| .clone(true, false) | Copiados | Copiados | No copiados |
| .clone(true, true) | Copiados | Copiados | Copiados |
| .clone(true) | Copiados | Copiados | Copiados; el segundo argumento sigue al primero |
Insertar un elemento existente en un único destino con .appendTo() lo mueve. Para mantener el original, clona primero. Son elementos separados del modelo de objetos del documento, DOM, así que cambiar el título de la copia no cambia el original.
Ejemplo completo de datos y clics en tarjetas
Guarda todo el código en UTF-8 como clone-demo.html y ábrelo en el navegador. jQuery 4.0.0 se carga de su red oficial de distribución de contenidos, CDN; requiere internet, sin instalación. Los tres modos, clics, datos compartidos y Reset se ejecutaron con 3.7.1 y 4.0.0.
La raíz original almacena count y kind; el botón interno Increment tiene un manejador directo. El código reinicia explícitamente el contador y el número mostrado de cada copia en cero. Clonar no reinicia contadores automáticamente.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Clone structure, data and events</title>
<style>
body { font: 16px/1.6 sans-serif; margin: 24px; }
.card { padding: 14px; margin: 12px 0; border: 1px solid #8aa; }
.card p { margin: 4px 0; }
button { margin: 4px; padding: 8px; }
</style>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
</head>
<body>
<h1>Clone structure, data and events</h1>
<div class="card" id="source">
<p class="label">Original</p>
<p>Count: <span class="count">0</span></p>
<p>Data: <span class="data">stored</span></p>
<button type="button" class="increment">Increment</button>
</div>
<button type="button" id="plain">Clone structure</button>
<button type="button" id="parent">Clone parent data</button>
<button type="button" id="full">Clone events</button>
<button type="button" id="reset">Reset</button>
<div id="copies"></div>
<p id="result" aria-live="polite"></p>
<script>
$(function () {
const $source = $("#source").data({ count: 0, kind: "stored" });
let serial = 1;
function report() {
$("#result").text(`source=${$source.data("count")} | copies=${$("#copies > .card").length}`);
}
$source.find(".increment").on("click", function () {
const $card = $(this).closest(".card");
const count = $card.data("count") + 1;
$card.data("count", count).find(".count").text(count);
report();
});
function copy(withData, deep) {
const $copy = $source.clone(withData, deep);
$copy.attr("id", "copy-" + serial);
$copy.find(".label").text("Copy " + serial++);
$copy.data("count", 0).find(".count").text(0);
$copy.find(".data").text($copy.data("kind") || "none");
$copy.appendTo("#copies");
report();
}
$("#plain").on("click", () => copy(false, false));
$("#parent").on("click", () => copy(true, false));
$("#full").on("click", () => copy(true, true));
$("#reset").on("click", function () {
$("#copies").empty();
serial = 1;
$source.data("count", 0).find(".count").text(0);
report();
});
report();
});
</script>
</body>
</html>
Al principio solo existe el original:
source=0 | copies=0
- Pulsa Increment del original una vez para obtener Count 1.
- Clone structure copia estructura sin kind ni manejador. Copy 1 muestra Data none y su botón mantiene cero.
- Clone parent data copia kind y muestra stored, pero no el manejador del botón descendiente; no incrementa.
- Clone events incluye los manejadores descendientes. Copy 3 pasa a 1 y el original permanece en 1.
- Reset elimina las copias y reinicia contador original y numeración. No vuelve a registrar el manejador original, así un clic sigue incrementando una vez tras repetir Reset.
Antes de insertar, la raíz recibe un ID único como copy-1; las partes internas usan clases. Si los descendientes tienen ID o referencias label for y aria-controls, actualiza identificadores y referencias juntos.
Copiar objetos y arrays anidados explícitamente
Los objetos y arrays de .data() copiados por .clone(true) pueden seguir compartidos. Ejecuta este fragmento completo en la consola de desarrollo; usa elementos temporales sin insertar.
const $original = $("<div>").data("options", { tags: ["a"] });
const $shared = $original.clone(true);
$shared.data("options").tags.push("b");
console.log($original.data("options").tags.join(", "));
const $independent = $original.clone(true).data("options", {
tags: [...$original.data("options").tags]
});
$independent.data("options").tags.push("c");
console.log($original.data("options").tags.join(", "));
console.log($independent.data("options").tags.join(", "));
a, b
a, b
a, b, c
Añadir b mediante la primera copia cambia también el original a a, b porque ambos usan el mismo options. La copia independiente recibe options y tags nuevos; añadir c mantiene el original en a, b. Se copia una estructura conocida con un array de cadenas, no cualquier objeto profundamente anidado.
Estado de formularios, eventos y problemas
No supongas que todos los controles copian igual su estado actual. La documentación distingue input de textarea/select. Comprueba los valores necesarios y considera asignar selecciones y notas explícitamente con .val() después de clonar.
Copiar todos los manejadores no es la única opción para nuevas tarjetas. La delegación con .on() en un padre persistente puede tratar descendientes nuevos. Combinar manejadores directos copiados y delegación puede duplicar acciones; elige y comprueba el enfoque necesario.
Si no ves la copia, revisa inserción y destino. Para botones inactivos, comprueba si el manejador estaba en raíz o descendientes y revisa ambos argumentos. Un conjunto vacío produce copia vacía; ID duplicados pueden desviar selectores y etiquetas. Examina también Network y Console.




