jQuery / Method / .clone() - Ausgewählte Elemente kopieren

jQuerys .clone() erzeugt ein neues jQuery-Objekt mit Kopien der ausgewählten Elemente, Nachfahren und Texte. Das fügt sie noch nicht ins Dokument ein; dafür dient etwa .appendTo(). jQuery-Ereignisse und Daten sind standardmäßig ausgeschlossen und werden separat per Argument gesteuert.

Struktur, Verschieben und Ereignisoptionen

Die Dokumentation zu .clone() meint mit tiefer Strukturkopie auch Kindelemente. Das verspricht keine vollständige Unabhängigkeit aller Ereignisse, .data()-Objekte und verschachtelten Werte. deepWithDataAndEvents als zweites Argument steuert Nachfahrenereignisse und -daten, nicht das Kopieren der DOM-Kinder selbst.

Ausdruck Element und Nachfahrenstruktur Ereignisse/Daten am Wurzelelement Ereignisse/Daten der Nachfahren
.clone() Kopiert Nicht kopiert Nicht kopiert
.clone(true, false) Kopiert Kopiert Nicht kopiert
.clone(true, true) Kopiert Kopiert Kopiert
.clone(true) Kopiert Kopiert Kopiert; zweites Argument folgt dem ersten

Ein bestehendes Element mit .appendTo() in ein einziges Ziel einzufügen verschiebt es. Für den Erhalt des Originals klonen Sie zuerst und fügen die Kopie ein. Es sind getrennte Elemente des Document Object Model (DOM); ein geänderter Kopietitel verändert das Original nicht.

Vollständiges Kartenbeispiel für Daten und Klicks

Speichern Sie alles als UTF-8 in clone-demo.html und öffnen Sie es im Browser. jQuery 4.0.0 wird über das offizielle Content Delivery Network (CDN) geladen; Internet ist nötig, eine Installation nicht. Alle drei Modi, Klickverhalten, Datenteilung und Reset wurden mit 3.7.1 und 4.0.0 ausgeführt.

Das Original speichert count und kind am Wurzelelement; der innere Increment-Button hat einen direkt gebundenen Handler. Der Code setzt Kopiezähler und sichtbare Zahl ausdrücklich auf null. Klonen allein setzt keinen Zähler zurück.

<!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>

Anfangs existiert nur das Original:

source=0 | copies=0
  1. Drücken Sie am Original einmal Increment, sodass Count 1 ist.
  2. Clone structure kopiert Struktur ohne kind oder Handler. Copy 1 zeigt Data none; ihr Button belässt den Zähler bei null.
  3. Clone parent data kopiert kind und zeigt stored, jedoch keinen Handler des untergeordneten Buttons. Er erhöht nichts.
  4. Clone events schließt Nachfahrenhandler ein. Copy 3 erhöht sich auf 1; das Original bleibt ebenfalls 1.
  5. Reset entfernt Kopien und setzt Originalzähler und Nummerierung zurück. Der Originalhandler wird nicht erneut gebunden; pro Klick bleibt es bei einem Aufruf.

Vor dem Einfügen wird die Wurzel-ID eindeutig, etwa copy-1. Innere Teile verwenden Klassen. Haben Nachfahren IDs oder Verweise wie label for und aria-controls, ändern Sie IDs und Verweise gemeinsam.

Verschachtelte Objekte und Arrays ausdrücklich kopieren

Objekte und Arrays in mit .clone(true) kopiertem .data() können geteilt bleiben. Führen Sie diesen vollständigen Teilcode in der Entwicklerkonsole aus. Er verwendet nicht eingefügte temporäre Elemente.

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

b in der ersten Kopie verändert auch das Original zu a, b, weil beide dasselbe options-Objekt verwenden. Die unabhängige Kopie erhält neues options samt neuem tags-Array. Ihr c lässt das Original bei a, b. Dies kopiert eine bekannte Struktur mit Zeichenkettenarray und ist keine allgemeine tiefe Kopie beliebiger Objekte.

Formularzustand, Ereignisdesign und Fehlerprüfung

Nehmen Sie nicht an, dass jeder Formulartyp seinen aktuellen Zustand identisch kopiert. Die offizielle Dokumentation unterscheidet dynamische input-Zustände von textarea/select. Prüfen Sie benötigte Werte und setzen Sie etwa Auswahl und Notizen nach dem Klonen ausdrücklich mit .val().

Für neue Karten müssen nicht zwingend alle Handler kopiert werden. Delegation per .on() an einem beständigen Elternteil kann neue Nachfahren behandeln. Kopierte direkte Handler plus Delegation können dieselbe Aktion doppelt ausführen; wählen und prüfen Sie den passenden Ansatz.

Fehlt die Kopie, kontrollieren Sie Einfügen und vorhandenes Ziel. Bei inaktiven Buttons prüfen Sie Wurzel- gegenüber Nachfahrenbindung und beide Argumente. Eine leere Auswahl ergibt eine leere Kopie; doppelte IDs können Selektoren und Labels fehlleiten. Prüfen Sie außerdem Network und Console.