JavaScript | HTML要素を追加したい時に使うinnerHTMLとinsertAdjacentHTML

# JavaScriptでHTML要素を追加したい

動的にHTML要素を追加したい時など、JavaScriptでHTMLをいじくりたいなぁというときは
`insertAdjacentHTML`を使います。

この`insertAdjacentHTML`と同じようなことができる`innerHTML`というものがあります。

どっちが良いの？ 違いは？ ということで調べてみました。

## insertAdjacentHTML を使おう

結論から言うと、`insertAdjacentHTML`を使う方が良い。

### insertAdjacentHTML

>insertAdjacentHTML() は、第二引数で指定するテキストを HTML または XML としてパースし、
>その結果であるノードを DOM ツリー内の指定された位置（第一引数で指定）に挿入します。
>これは挿入先の要素を再度パースするものではないため、既存の要素や要素内部の破壊を伴いません。
>余分なシリアル化のステップを回避できる分、 innerHTML への代入による直接的な操作よりもはるかに高速な動作となります。
>
>[element.insertAdjacentHTML](https://developer.mozilla.org/ja/docs/Web/API/Element/insertAdjacentHTML)

### innerHTML

>Element オブジェクトの innerHTML プロパティは、要素内の HTML または XML のマークアップを取得したり設定したりします。
>要素の内容を置き換えるというより、文書に HTML を挿入するという場合には、 insertAdjacentHTML() メソッドを使用してください。
>
>[Element.innerHTML](https://developer.mozilla.org/ja/docs/Web/API/Element/innerHTML)

`insertAdjacentHTML`が良いんだろうなと言うことはバシバシ伝ってきます。

## 既存の要素や要素内部の破壊!?

**破壊**という恐ろしいワードが気になる方のために簡単なサンプルを用意してみました。

```html:corruption.html
<html>
    <body>
        <div id="container">
            <button id="button">クリック！</button>
        </div>
    </body>
</html>

<script>
    const button = document.getElementById('button');
    button.addEventListener('click', function () {
        const container = document.getElementById('container');
        container.innerHTML = '<div>ボタンをクリックしました</div>' + container.innerHTML;
    });
</script>
```

- 「クリック！」ボタンを表示
- JavaScriptで`innerHTML`を使ってボタンの前に「ボタンをクリックしました」と表示するイベントを追加

少し強引な例ですが、ボタンを2回目以降はボタンをクリックしても
「ボタンをクリックしました」が表示されることはありません。

### 破壊手順（クリックイベント内の処理）の解説

1.　`#container`内の要素を`getElementById`で取得
2.　`#container`内の要素である`#button`を`innerHTML`でHTML文字列として取得してbuttonHtml変数に格納
3.　`#container`内の要素を`<div>ボタンをクリックしました</div>`とbuttonHtmlを結合して`innerHTML`で書き換える
4.　「クリック！」ボタンは**新しいボタン要素**として描画されている
5.　`addEventListener`は初回の画面表示にしか走らないのでクリックイベントが追加されることはない

※2.がないとボタンが消えてしまいます

### insertAdjacentHTMLで実装してみる

```html:no_corruption.html
<html>
    <body>
        <div id="container">
            <button id="button">クリック！</button>
        </div>
    </body>
</html>

<script>
    const button = document.getElementById('button');
    button.addEventListener('click', function () {
        container.insertAdjacentHTML('afterbegin', '<div>ボタンをクリックしました</div>');
    });
</script>
```

ボタンをクリックする度に「ボタンをクリックしました」が表示されるようになります。

`insertAdjacentHTML`は第一引数に`position`があります。

>element.insertAdjacentHTML(position, text);

1. beforebegin: `element`の直前に挿入
2. afterbegin: `element`内部の、最初の子要素の前に挿入
3. beforeend: `element`内部の、最後の子要素の後に挿入
4. afterend: `element`の直後に挿入

```html
<html>
    <body>
        <!-- 1. beforebegin -->
        <div id="container">
            <!-- 2. afterbegin -->
            <button id="button">クリック！</button>
            <!-- 3. beforeend -->
        </div>
        <!-- 4. afterend -->
    </body>
</html>
```

### insertAdjacentHTMLは高速

今回参考にした記事では実際に計測されていました。
10倍近い差が出たそうですが、記事のコメントにはブラウザによって差異があるとの報告もありました。

[innerHTML より insertAdjacentHTML を使う](https://qiita.com/amamamaou/items/624c22adec32515e863b)

## 最後に

HTMLの大部分を書き換える際は`innerHTML`でも良いのかも知れませんが
そのようなケースは稀でしょうから、`insertAdjacentHTML `を使うと言う認識で問題ないのかと思います。

また、HTML要素を追加したいという目的であれば、`insertAdjacentHTML`ではなく
[Document.createElement()](https://developer.mozilla.org/ja/docs/Web/API/Document/createElement)や[Node.appendChild](https://developer.mozilla.org/ja/docs/Web/API/Node/appendChild)を使うという実装も考えられます。

そのときどきに合ったベストな方法で実装するしかない、というところでしょうか。

おしまい。