JavaScriptにおけるDOMノード操作

JavaScriptで要素を取得する際には主に2つの方法が用いられます。

ノード概要

ウェブページ内のすべてのコンテンツはノード(タグ、属性、テキスト、コメントなど)として扱われ、DOMではnodeで表されます。HTML DOMツリー内のすべてのノードはJavaScriptでアクセス可能であり、HTML要素(ノード)は変更、作成、削除可能です。

ノード属性

ノードは少なくともnodeType(ノードタイプ)、nodeName(ノード名)、nodeValue(ノード値)の3つの基本属性を持ちます。

要素ノード: nodeTypeは1
属性ノード: nodeTypeは2
テキストノード: nodeTypeは3(テキスト、空白、改行を含む)

実際の開発では主に要素ノードを操作します。

ノード階層

DOMツリーを利用してノードを異なる階層関係に分類できます。一般的なのは親子兄弟関係です。

1. 親ノード

node.parentNode

例:

<body>
    <div class="demo">
        <div class="box">
            <span class="qr-code">×</span>
        </div>
    </div>

    <script>
        // 1. 親ノード parentNode
        var qrCode = document.querySelector('.qr-code');
        // var box = document.querySelector('.box');
        // 返されるのは要素の直近の親ノード(親要素)で、親ノードがない場合はnullを返す
        console.log(qrCode.parentNode);
    </script>
</body>

parentNodeプロパティは指定ノードの親ノードを返します。注意点として、最近の親ノードを返す点と、親ノードがない場合はnullを返す点です。

2. 子ノード

parentNode.childNodes(標準)

parentNode.childNodesは指定ノードの子ノードのコレクションを返します。このコレクションは即時更新されます。 注意: 返される値にはすべての子ノード(要素ノード、テキストノードなど)が含まれます。要素ノードだけを取得したい場合は専用の処理が必要です。そのため、childNodesの使用は推奨されません。要素ノードだけを取得するためのループ処理例:

var list = document.querySelector('ul');
for(var i = 0; i < list.childNodes.length;i++) {
if (list.childNodes[i].nodeType == 1) {    // list.childNodes[i] は要素ノード
    console.log(list.childNodes[i]);}
}

非標準ですが、ブラウザサポートが広い方法として以下があります:

parentNode.children(非標準)

parentNode.childrenは読み取り専用のプロパティで、すべての子要素ノードを返します。他のノードは返しません(これは重点的に学ぶべき点です)。非標準ですが、ブラウザでのサポートが充実しているため安心して使用可能です。

<body>
    <ul>
        <li>私はliです</li>
        <li>私はliです</li>
        <li>私はliです</li>
        <li>私はliです</li>
    </ul>

    <script>
        // DOM APIによる取得
        var list = document.querySelector('ul');
        var items = list.querySelectorAll('li');
        // 1. 子ノード childNodes すべての子ノードを含む
        console.log(list.childNodes);
        console.log(list.childNodes[0].nodeType); // ノードタイプ
        console.log(list.childNodes[1].nodeType);
        // 2. children すべての子要素ノードを取得(開発でよく使う)
        console.log(list.children);
    </script>
</body>

その他の子ノード取得方法:

//firstChild は最初の子ノードを返す。見つからない場合はnullを返す。すべてのノードを含む。
parentNode.firstChild   

//lastChild は最後の子ノードを返す。見つからない場合はnullを返す。すべてのノードを含む。
parentNode.lastChild 

//firstElementChild は最初の子要素ノードを返す。見つからない場合はnullを返す。 
parentNode.firstElementChild 

//lastElementChild は最後の子要素ノードを返す。見つからない場合はnullを返す。
parentNode.lastElementChild

実際の開発では、firstChildとlastChildはすべてのノードを含むため操作が不便です。firstElementChildとlastElementChildは互換性の問題があります。この場合、どのように最初の子要素ノードや最後の子要素ノードを取得すればよいでしょうか? 解決策: 最初の子要素ノードを取得するには

parentNode.children[0] 

最後の子要素ノードを取得するには

parentNode.children[parentNode.children.length - 1]  

例:

<body>
    <ol>
        <li>私はli1です</li>
        <li>私はli2です</li>
        <li>私はli3です</li>
        <li>私はli4です</li>
        <li>私はli5です</li>
    </ol>
    <script>
        var list = document.querySelector('ol');
        // 1. firstChild は最初の子ノードを返す(テキストノードや要素ノードを含む)
        console.log(list.firstChild);
        console.log(list.lastChild);
        // 2. firstElementChild は最初の子要素ノードを返す(IE9からサポート)
        console.log(list.firstElementChild);
        console.log(list.lastElementChild);
        // 3. 実際の開発で使われる方法(互換性問題なしで最初の子要素ノードを返す)
        console.log(list.children[0]);
        console.log(list.children[list.children.length - 1]);
    </script>
</body>

3. 兄弟ノード

//nextSibling は現在の要素の次の兄弟ノードを返す。見つからない場合はnullを返す。すべてのノードを含む。
node.nextSibling  

//previousSibling は現在の要素の前の兄弟ノードを返す。見つからない場合はnullを返す。すべてのノードを含む。
node.previousSibling   

//nextElementSibling は現在の要素の次の兄弟要素ノードを返す。見つからない場合はnullを返す。 
node.nextElementSibling  

//previousElementSibling は現在の要素の前の兄弟ノードを返す。見つからない場合はnullを返す。 
node.previousElementSibling    

例:

<body>
    <div>私はdivです</div>
    <span>私はspanです</span>
    <script>
        var div = document.querySelector('div');
        // 1.nextSibling 次の兄弟ノード(要素ノードやテキストノードを含む)
        console.log(div.nextSibling);
        console.log(div.previousSibling);
        // 2. nextElementSibling 次の兄弟要素ノード
        console.log(div.nextElementSibling);
        console.log(div.previousElementSibling);
    </script>
</body>

注意: nextElementSiblingとpreviousElementSiblingはIE9以上でのみサポートされています。 互換性のある関数をラッピングする:

function getNextElementSibling(element) {
      var el = element;
      while (el = el.nextSibling) {
        if (el.nodeType === 1) {
            return el;
        }
      }
      return null;
    }  

4. ノードの作成

document.createElement('tagName')

document.createElement()メソッドは指定されたtagNameのHTML要素を作成します。これらの要素は元々存在しないため、動的に生成される要素ノードとも呼ばれます。

5. ノードの追加

node.appendChild() 

node.appendChild()メソッドは指定された親ノードの子ノードリストの末尾にノードを追加します。CSSのafter擬似要素に似ています。

node.insertBefore(child, 指定要素) 

node.insertBefore()メソッドは親ノードの指定された子ノードの前にノードを追加します。CSSのbefore擬似要素に似ています。

6. ノードの削除

node.removeChild(child) 

node.removeChild()メソッドはDOMから子ノードを削除し、削除されたノードを返します。

作成、追加、削除の例:

<body>
    <ul>
        <li>123</li>
    </ul>
    <script>
        // 1. 要素ノードの作成
        var item = document.createElement('li');
        // 2. ノードの追加 node.appendChild(child)  nodeは親、childは子。末尾に追加。配列のpushに似た。
        var list = document.querySelector('ul');
        list.appendChild(item);
        // 3. ノードの挿入 node.insertBefore(child, 指定要素);
        var newItem = document.createElement('li');
        list.insertBefore(newItem, list.children[0]);
        // 4. ノードの削除
        list.removeChild('li');
    </script>
</body>

7. ノードの複製(クローン)

node.cloneNode() //浅コピー
node.cloneNode(true) //深コピー

node.cloneNode()メソッドは呼び出し元のノードのコピーを返します。クローンノード/コピーノードとも呼ばれます。 注意:

1. 引数が空またはfalseの場合、浅コピーとなり、ノード自体のみをコピーし、子ノードはコピーしません。
2. 引数がtrueの場合、深コピーとなり、ノード自体とすべての子ノードをコピーします。

簡易版コメント投稿機能

    <style>
        * {
            margin: 0;
            padding: 0;
        }
        
        body {
            padding: 100px;
        }
        
        textarea {
            width: 200px;
            height: 100px;
            border: 1px solid pink;
            outline: none;
            resize: none;
        }
        
        ul {
            margin-top: 50px;
        }
        
        li {
            width: 300px;
            padding: 5px;
            background-color: rgb(245, 209, 243);
            color: red;
            font-size: 14px;
            margin: 15px 0;
        }
    </style>

<body>
    <textarea name="" id=""></textarea>
    <button>投稿</button>
    <ul>
    </ul>
    <script>
        // 1. 要素の取得
        var postButton = document.querySelector('button');
        var inputArea = document.querySelector('textarea');
        var commentList = document.querySelector('ul');
        // 2. イベントの登録
        postButton.onclick = function() {
            if (inputArea.value == '') {
                alert('内容が入力されていません');
                return false;
            } else {
                // console.log(inputArea.value);
                // (1) 要素の作成
                var item = document.createElement('li');
                // 作成したitemに値を設定
                item.innerHTML = inputArea.value;
                // (2) 要素の追加
                // commentList.appendChild(item);
                commentList.insertBefore(item, commentList.children[0]);
            }
        }
    </script>
</body>

タグ: DOM操作 javascript ノード操作 要素追加 ノード削除

5月26日 17:46 投稿