web-dev-qa-db-ja.com

イベントリスナーでDOMノードをコピーする方法は?

私は試した

_node.cloneNode(true); // deep copy
_

node.addEventListener("click", someFunc);を使用して追加したイベントリスナーをコピーしていないようです。

Dojoライブラリーを使用します。

49
Chakradar Raju

cloneNode()は、イベントリスナーをコピーしません。実際、イベントリスナーがアタッチされると、DOMを介してイベントリスナーを保持する方法がないため、オプションは次のとおりです。

  • すべてのイベントリスナーをクローンノードに手動で追加します
  • すべてのイベントハンドラーが元とクローンの両方を含むノードに接続されるように、イベント委任を使用するようにコードをリファクタリングします。
  • Node.addEventListener()を囲むラッパー関数を使用して、各ノードに追加されたリスナーを追跡します。これは、jQueryの clone() メソッドが、たとえば、イベントリスナーを使用してノードをコピーする方法です。
63
Tim Down

イベント委任の例。

Tim Downの答えを読んだ後、委任されたイベントは実装が非常に簡単で、私が抱えていた同様の問題を解決できることがわかりました。 DojoではなくJQueryにありますが、具体的な例を追加すると思いました。

Semantic UIでアプリケーションを再スキーしています。これには、メッセージの閉じるボタンを機能させるためにJSの一部が必要です。ただし、メッセージは、ライブラリのdocument.importNodeを使用してHTMLテンプレートタグから複製されます。つまり、イベントハンドラーを新しいHTMLのテンプレートに添付したとしても、それらは複製中に失われます。

メッセージングライブラリはフロントエンドフレームワークにとらわれないため、複製中に単純に再アタッチするために、Timのオプション1を実行することはできません。 (興味深いことに、以前のフロントエンドはZurb Foundationにあり、Zurb Foundationは "data-closable"属性を使用していましたが、その機能はクローン作成プロセスを生き残ります)。

提案された通常のイベント処理はこのようなものでした

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

App-loadでの「.message」という問題は、単一のテンプレートにのみ一致し、後でWebソケットを介して到着する実際のメッセージには一致しません。

これを委任することは、メッセージが複製されるコンテナにイベントを添付することを意味しました<div id="user-messages">

したがって、次のようになります。

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

これはすぐに機能し、イベントサブをラップする3番目のオプションのような複雑な作業を保存します。

Dojoでの同等物 は概念的にはかなり似ています。

2
scipilot

これは質問に正確に答えるものではありませんが、ユースケースが要素をcopyingではなくmovingを許可する場合、使用できます removeChild とともに appendChild を使用すると、イベントリスナーが保持されます。例えば:

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

これが @ JeromeJ がコメントで説明したことです。このHTMLコードを使用して初期要素を作成します。

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

この要素を複製すると、結果は同じハンドラーを持ち、「this」は複製された要素を指します。

ONCLICKハンドラーをJavaScriptに簡単に追加できると便利です。このアプローチは、コードの一部をHTMLで記述する必要があることを意味します。

0