LoginSignup
29
23

More than 3 years have passed since last update.

【JavaScript】一旦初心に戻ってDOM操作を学び直す

Last updated at Posted at 2019-08-13

なぜ学び直すのかとその目的

学びの参考一覧
https://developer.mozilla.org/ja/docs/Web/API/NodeList
https://ginpen.com/2015/12/22/nodelist-vs-htmlcollection/
・書籍「JavaScript本格入門」p282~p293

getElementByIdとか、querySelectorとかを使う簡単なDOM操作には結構慣れてきました。
でも、複数のDOM操作をする場合にあまり効率よくできてないんじゃないかな?
と思うことがあります。itemやらバブリングやらを使いこなして、スッキリしたコードをかけるようになるべく再入門です。

HTMLコレクション

DOMを取得するにあたって、複数のものを習得した場合の戻り値の1つがHTMLCollectionです。

  • getElementsByTagName
  • getElementsByClassName
  • getElementsByName

この辺の戻り値がHTMLCollectionになっています。

HTMLCollection取得

let myCollection = document.getElementsByTagName('meta');
console.log(myCollection);

こちらが結果になります。HTMLCollectionというプロトタイプを継承しています。
スクリーンショット 2019-08-13 9.09.44.png

こいつらをうまく扱うためには、まず道具を知るべしです。
以下がHTMLCollecitonオブジェクトのメンバーになります。

メンバー 概要
length 要素数
item(i) i番目の要素(0 ~ length-1の範囲)
namedItem(name) id,またはname属性が一致する要素の取得
let myCollection = document.getElementsByTagName('meta');
console.log(myCollection.item(2).content);
console.log(myCollection[2].content);

コードの2行目と3行目は同じ意味合いで、要はitemはブラケット構文でも記述できる、ということです。

もう1つのノードの集合体,NodeList

  • Node.childNodes
  • querySelectorAll

この辺の戻り値はNodeListと呼ばれるオブジェクトです。
HTMLCollectionと利用できるメンバーもほぼ同じですが、異なる点もあります。
異なる点としては、

HTMLCollectionは動的
NodeListは静的

ドユコトー?
だと思うので例を見てみましょう。

HTML最初の状態
<div class="one"></div>
<div class="two"></div>
javascriptでの操作
let myNodeList = document.querySelectorAll('div');  //ノードリスト
let myHTMLCollection = document.getElementsByClassName('bom'); //HTMLコレクション

let newNode = document.createElement('div'); 
newNode.classList.add('bom');
document.body.appendChild(newNode); //新しく<div class="bom"></div>を追加する

console.log(myNodeList.length); //戻り値 2
console.log(myHTMLCollection.length); //戻り値 3

NodeListは静的なので、取得後DOMの操作があってもそれが反映されていません。
対してHTMLCollectionは取得後のDOM操作も感知していて動的です。

ノードウォーキングについて

document.xxxxxっていう要素の取得って...
毎回毎回documentから辿ってってるわけじゃないですか。
例えば3階にある電気屋の炊飯器と冷蔵庫を見にきたのに、
「ここが3階で...あ、炊飯器だ! よし、また一階に戻って冷蔵庫を探そう!」
っていうのと同じでかなり無駄ですね。

そこで特定のノードを基点に相対的な位置関係からノード取得をする方法が役に立ちます。
ノードウォーキングと呼ばれています。

基点のノードをgetXXXX/queryXXXX 系で取得して、そこからノードウォーキングしていけば良さげです。

HTML
<body>
    <form>
        <label for="animal">動物を選んでね</label>
        <select id="animal">
            <option value="犬"></option>
            <option value="ネコ">ネコ</option>
            <option value="コモドオオトカゲ">コモドオオトカゲ</option>
        </select>
    </form>
</body>
子要素以下の取得
let basePoint = document.getElementById('animal');
let opts = basePoint.childNodes;  //ここに子要素以下が格納される

ただ注意しなければいけないのが、childNodesプロパティが取得するノードはNodeListである点と、ノードが要素ノードだけでない
という点です。空白ノードやテキストノードを含んでしまっています。
詳しくは下記のリンク等を参考にしてください。
https://www.javadrive.jp/javascript/dom/index4.html

以下、console.log(basePoint.childNodes)の結果です。

スクリーンショット 2019-08-13 10.21.55.png

そこでnodeの種類を判別しなければなりませんね。
nodeTypeプロパティを使用すればそれができます!
nodeTypeで判別できるノードの種類はかなりのものがあるんですが、以下を抑えておけば実務では使えそうです。

戻り値 ノードの種類
1 要素ノード
2 属性ノード
3 テキストノード

以上を踏まえて、上記のHTMLのoptionを取得してみます。

ノードウォーキングによる要素取得
let basePoint = document.getElementById('animal');
let opts = basePoint.childNodes; //ノードウォーキングの基点

for(let i = 0;i < opts.length; i++){ //取得した全てのノードをチェック
    if(opts[i].nodeType === 1){  //要素ノードなら
        console.log(opts[i].value);   //valueを出力
    }
}

子要素リストのその他の取得方法

その他の子要素取得方法
let child = baseNode.firstElementChild
while(child){
   console.log(child.value);
   child.nextElementSibling;  //兄弟要素取得
}

firstElementChild・・・要素直下の最初の子要素を取得
nextElementSibling・・・要素の次の兄弟要素を取得

どちらも要素エレメントしか取得しないので、nodeType判定が不要な分スッキリしています。
このコードは子要素の兄弟エレメントがなくなるまでループをかけることで、子要素全てを取得していますね。

感想

とりあえず取得できればOK!で今までコーディングしてきたので、
ノードウォーキングはあまり意識していませんでした。今後の役に立ちそうです。
次回はイベント系の処理をしっかり学び直します!

29
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
23