Help us understand the problem. What is going on with this article?

jQueryのappendで取得元が消えてしまうときの回避方法

はじめに

エレメントから要素を取得して、その要素を別の場所にコピーする処理をjQueryのappendでしようとしていたのですが、取得元が消えてしまいハマってしまったので、その回避策のメモです。

事象

以下のような画面があったとして、「テストタイトル1」をクリックすると、「テストタイトル2」の下に「テスト内容」がコピーされるプログラムを作成したかったとします。

テストタイトル1 // ① クリック
テスト内容
テストタイトル2 // ② この下に「テスト内容」がコピーされる

そこで、以下のようなHTMLとJavascriptを実装します。

<html>
  <head>
    <meta charset="utf-8">
    <title>テスト</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  </head>
  <body>
  <div id="test" class="test">
    <div class="test-title-1">
      テストタイトル1
      <div class="test-contents">テスト内容</div>
    </div>
    <div class="test-title-2">
      テストタイトル2
    </div>
  </div>
  </body>
  <script>
    $('.test-title-1').on('click', function(){
      const target = event.currentTarget; // クリックした要素(test-title-1)を取得
      const testContents = $(target).find('.test-contents'); // test-contentsクラスの要素取得
      $('.test-title-2').append(testContents); // test-title-2クラスへappend
    });
  </script>
</html>

すると、なぜか結果は以下のようになり、「テストタイトル1」直下のテスト内容が消えてしまいます。

テストタイトル1
テストタイトル2
テスト内容

原因

jQueryオブジェクトのappend()は追加or移動という仕様でした。

公式サイトを見ると、以下のように記載がありました。

If an element selected this way is inserted into a single location elsewhere in the DOM, it will be moved into the target (not cloned)
(日本語訳)
「この方法で選択された要素がDOMの他の場所の単一の場所に挿入された場合、それはターゲットに移動されます」

つまり、取得したDOMはappendすると、別の要素へ移動されてしまうのです。。。

回避策

これを回避するには、appendする時に、変数を複製すればOKです。

先ほどのサンプルプログラムを利用すると、具体的には、clone()メソッドを以下のように使います。

<html>
  <head>
    <meta charset="utf-8">
    <title>テスト</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  </head>
  <body>
  <div id="test" class="test">
    <div class="test-title-1">
      テストタイトル1
      <div class="test-contents">テスト内容</div>
    </div>
    <div class="test-title-2">
      テストタイトル2
    </div>
  </div>
  </body>
  <script>
    $('.test-title-1').on('click', function(){
      const target = event.currentTarget;
      const testContents = $(target).find('.test-contents').clone(); // ここにclone()を追加
      $('.test-title-2').append(testContents);
    });
  </script>
</html>

すると、取得した要素は一度クローン(複製)されるため、appendが移動するのは複製した要素となるので、以下のように正常にコピーできます。

テストタイトル1 // ① クリック
テスト内容
テストタイトル2
テスト内容 // ② テスト内容が正常にコピーされる

さいごに

2020年から個人ブログはじめました!

フリーランスエンジニアになって得た知識と経験をもとに、フリーランスエンジニアに関する情報をはじめ、IT技術情報や業界情報、エンジニアライフハック等のコンテンツを配信していく予定です。

まだまだ記事数は少ないのですが、週単位で更新してますので、もしご興味ございましたら、みていただけると嬉しいです。

https://yacchi-engineer.com/

さいごまでお読みいただき、ありがとうございました。

yacchi1123
一部上場SIer企業4年勤務後、フリーランスエンジニアへ。自身のエンジニアとしての経験や失敗、技術メモを発信していきます。
https://yacchi-engineer.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away