カテゴリー
【Javascript活用講座】もっとHTML要素を上手く操作するためのappendChildの使い方
※ 当ページには【広告/PR】を含む場合があります。
2021/12/22
2022/10/03

たまに思いついたときに唐突に出てくるjavascriptのテクニカルな話題です。
今回はHTMLを直接スクリプトからDOM操作するために必須となる
特にappendChildの面白い特徴である
appendChildメソッドの基本
「appendChildメソッド」はその名の通りHTML要素(ノード)の下に子要素(ノード)を追加するだけです。
以下のHTMLファイルをブラウザで直に開いて確認してみましょう。
<!DOCTYPE html>
<html lang="ja">
<html>
<meta charset="utf-8"/>
<body>
<div id="wrapper"></div>
<script>
document.addEventListener("DOMContentLoaded", () => {
const parent = document.getElementById('wrapper');
const child = document.createElement('p');
child.textContent = 'appendChildメソッドのテストです。';
//👇親ノードに子ノードを追加する
parent.appendChild(child)
});
</script>
</body>
</html>
結果は以下のようになります。

このようにappendChildメソッドはとてもシンプルな機能です。
シンプルな故に、ほとんどの人は
今回はこのポイントを良く理解してみましょう。
結論から先に言うと、
先程のindex.htmlのスクリプト中身を以下に変更します。
document.addEventListener("DOMContentLoaded", () => {
const parent = document.getElementById('wrapper');
const child = document.createElement('p');
child.textContent = 'appendChildメソッドのテストです。';
child === parent.appendChild(child) && console.log('オブジェクトが一致しました');
});

ということで、appendChildの返り値が追加した子要素と一致しました。
この返り値に一体なんの意味が...と感じる人もいるかもしれません。
一つはappendChildで最後に追加した要素を確認したいとき、もう一つは追加した子要素の下にさらに孫要素を追加したいとき、に使うことができます。
よってappendChildが追加した子要素そのものを返すため、先程のコードならば以下のようにワンライナーで書くことができます。
document.addEventListener("DOMContentLoaded", () => {
document.getElementById('wrapper').appendChild(document.createElement('p')).textContent = 'appendChildメソッドのテストです。';
});
createElementをカスタマイズする
もっとDOM操作をjavascriptから使いやすくするためは、
これは標準のcreateElementは一つの引数にHTMLタグ名を指定してHTML要素を生成するだけですので、あまり使い勝手の良いメソッドとは言えないことが理由です。
ということで
const createElement = (tagName, attrs) => {
const _e = document.createElement(tagName);
if (attrs) {
for (let attr in attrs) { _e[attr] = attrs[attr]; }
}
return _e;
};
これで前節のスクリプト部分はもっと見通しが良くすることができて、
const createElement = (tagName, attrs) => {
const _e = document.createElement(tagName);
if (attrs) {
for (let attr in attrs) { _e[attr] = attrs[attr]; }
}
return _e;
};
document.addEventListener("DOMContentLoaded", () => {
document.getElementById('wrapper').appendChild(createElement('p', {
textContent: 'appendChildメソッドのテストです。'
}));
});
とかなりスッキリとコードが書けるようになりました。
appendChildメソッドチェーン
ここからが気持ち的に本題です。
先程のから説明してきた通り、appendChildメソッドには追加した子要素の参照がそのまま返ってくる性質を利用しすることで、ワンライナーでDOMを直列的に生成することが可能になります。
これをここでは
一例を示すと、以下のようなスクリプトに変更します。
const createElement = (tagName, attrs) => {
const _e = document.createElement(tagName);
if (attrs) {
for (let attr in attrs) { _e[attr] = attrs[attr]; }
}
return _e;
};
document.addEventListener("DOMContentLoaded", () => {
document.getElementById('wrapper')
.appendChild(createElement('div', {
innerHTML: 'これは最初のDIVです。'
}))
.appendChild(createElement('div', {
innerHTML: 'これは2番めのDIVです。'
}))
.appendChild(createElement('div', {
innerHTML: 'これは3番めのDIVです。'
}))
.appendChild(createElement('span', {
innerHTML: 'これは3番めの中の最初のSPANです。'
}));
});
生成されたDOMを確認すると以下のようになっています。

ということで、appendChildメソッドチェーンを使えば容易にかつ効率的に階層的なDOMを作成することが可能となりました。
余談〜コンストラクタ関数でメソッドチェーンを拡張
先程まででappendChildメソッドチェーンでDOM階層の縦方向へ要素を繋げることができました。
欲を言えば、同じ階層にある要素をDOM構造の横のつながりも柔軟に増やしてみたいと思われるかも知れません。
この場合、
Class構文でも同じように出来るのですが、classを使うことが出来るのはECMAScript 6以降ですので、取り扱いには注意が必要です。
例えばDOMBuilderという名前でコンストラクタ関数を作ります。
function DOMBuilder(element) {
this.element = element;
};
DOMBuilder.prototype = {
appendChildren: function(domSeed) {
const children = [];
for (const el of domSeed) {
const child = this.element.appendChild(createElement(el[0], el[1]));
children.push(new DOMBuilder(child));
}
return children;
}
};
ポイントはプロトタイプで追加した
appendChildren
使い方は若干複雑になるのですが、以下のように使います。
const createElement = (tagName, attrs) => {
const _e = document.createElement(tagName);
if (attrs) {
for (let attr in attrs) { _e[attr] = attrs[attr]; }
}
return _e;
};
function DOMBuilder(element) {
this.element = element;
};
DOMBuilder.prototype = {
appendChildren: function(domSeed) {
const children = [];
for (const el of domSeed) {
const child = this.element.appendChild(createElement(el[0], el[1]));
children.push(new DOMBuilder(child));
}
return children;
}
};
document.addEventListener("DOMContentLoaded", () => {
(new DOMBuilder(document.getElementById('wrapper')))
.appendChildren([
['div', {innerHTML: 'これは最初のDIVです。'}],
['div', {innerHTML: 'これは2番目のDIVです。'}],
['div', {innerHTML: 'これは3番目のDIVです。'}],
]).forEach(dom => {
dom.appendChildren([
['p', {textContent: `${dom.element.innerHTML} の最初のPです。`}],
['p', {textContent: `${dom.element.innerHTML} の2番めのPです。`}],
]);
});
});
このindex.htmlを開くと、以下のようなDOM構造になっていることが分かります。

こうしてみるとappendChildだけで構成された、もっとも簡単なJavascriptフレームワークと見えなくもありません。
まとめ
今回はDOM操作でもっとも使うであろうappendChildメソッドの使い方を深く考察してみました。
確かにReactやAngularなどの高機能JSフレームワークならば作法に従って、複雑なDOM生成も簡単に操作できるのですが、今回のような「HTMLの標準関数」を良く理解しておくとなにかの時に役に立つと思います。
参考サイト
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー