web-dev-qa-db-fra.com

Comment copier un nœud DOM avec des écouteurs d'événements?

J'ai essayé

node.cloneNode(true); // deep copy

Il ne semble pas copier les écouteurs d'événements que j'ai ajoutés en utilisant node.addEventListener("click", someFunc);.

Nous utilisons la bibliothèque Dojo.

49
Chakradar Raju

cloneNode() ne copie pas les écouteurs d'événements. En fait, il n'y a aucun moyen de mettre la main sur les écouteurs d'événements via le DOM une fois qu'ils sont connectés, vos options sont donc les suivantes:

  • Ajoutez tous les écouteurs d'événements manuellement à votre nœud cloné
  • Refactorisez votre code pour utiliser la délégation d'événements afin que tous les gestionnaires d'événements soient attachés à un nœud qui contient à la fois l'original et le clone
  • Utilisez une fonction wrapper autour de Node.addEventListener() pour garder une trace des écouteurs ajoutés à chaque nœud. C'est ainsi que la méthode clone() de jQuery est capable de copier un nœud avec ses écouteurs d'événements, par exemple.
63
Tim Down

Exemple de délégation d'événement.

Après avoir lu la réponse de Tim Down, j'ai trouvé que les événements délégués étaient très faciles à implémenter, résolvant un problème similaire que j'avais. J'ai pensé que j'ajouterais un exemple concret, bien que ce soit dans JQuery pas Dojo.

Je re-skining une application dans Semantic UI, qui nécessite un petit morceau de JS pour faire fonctionner les boutons de fermeture de message. Cependant, les messages sont clonés à partir d'une balise de modèle HTML à l'aide de document.importNode dans une bibliothèque. Cela signifie que même si j'ai attaché les gestionnaires d'événements au modèle dans le nouveau HTML, ils sont perdus lors du clonage.

Je ne peux pas faire l'option 1 de Tim, simplement les ré-attacher pendant le clonage car la bibliothèque de messagerie est agnostique du framework frontal. (Fait intéressant, mon front-end précédent était dans Zurb Foundation, qui utilise un attribut "data-closable", dont la fonctionnalité survit au processus de clonage).

la gestion normale des événements suggérée était la suivante :

$('.message .close').on('click', function() {
    $(this)
    .closest('.message')
    .transition('fade');
});

Le problème étant ".message" au chargement de l'application ne correspond qu'au modèle unique, pas aux messages réels qui arrivent plus tard via les sockets Web.

Faire cela délégué, signifiait attacher l'événement au conteneur dans lequel les messages étaient clonés <div id="user-messages">

Cela devient donc:

$('#user-messages').on('click', '.message .close', function() {
    $(this)
    .closest('.message')
    .transition('fade');
});

Cela a fonctionné immédiatement, économisant tout travail complexe, comme la troisième option pour encapsuler les sous-événements.

Le équivalent Dojo semble assez similaire dans son concept.

2
scipilot

Cela ne répond pas exactement à la question, mais si le cas d'utilisation permet de déplacer l'élément plutôt que de copier , vous pouvez utiliser removeChild avec appendChild qui préservera les écouteurs d'événements. Par exemple:

function relocateElementBySelector(elementSelector, destSelector) {
  let element = document.querySelector(elementSelector);
  let elementParent = element.parentElement;
  let destElement = document.querySelector(destSelector);
  elementParent.removeChild(element);
  destElement.appendChild(element);
}
0
Richard Greenwood

C'est ce que @ JeromeJ décrivait dans un commentaire. Créez l'élément initial à l'aide de ce code HTML.

<DIV ONCLICK="doSomething(this)">touch me</DIV>

Lorsque vous clonez cet élément, le résultat aura le même gestionnaire et "this" pointera vers l'élément cloné.

Ce serait formidable si le gestionnaire ONCLICK pouvait facilement être ajouté en JavaScript. Cette approche signifie que vous devez écrire une partie de votre code en HTML.

0