知名度が低いウェブ標準ひとり Advent Calendar 2021 – 01 日目

初日は DOM の TreeWalker です。

jQuery の Traversing 系メソッドみたいなやつです。現在の「位置」をオブジェクトの内部状態に持ち、DOM ツリーを移動します。

基本的な使い方

document.createTreeWalker() でインスタンス生成します。walker.currentNode が移り変わる「位置」です。

<div id="wrapper">
  <div id="root">
    <div id="child1"></div>
    <div id="child2">
      <div id="child2-1"></div>
      <div id="child2-2"></div>
      <div id="child2-3"></div>
    </div>
    <div id="child3"></div>
  </div>
</div>
const elRoot = document.querySelector('#root');
const walker = document.createTreeWalker(elRoot, NodeFilter.SHOW_ELEMENT);

console.log('--- start', walker.currentNode.id); // => "root"

walker.firstChild();
console.log('first child', walker.currentNode.id); // => "child1"

walker.nextNode();
console.log('next', walker.currentNode.id); // => "child2"

walker.nextNode();
console.log('next (node)', walker.currentNode.id); // => "child2-1"

walker.parentNode();
console.log('parent', walker.currentNode.id); // => "child2"

walker.nextSibling();
console.log('next (sibling)', walker.currentNode.id); // => "child3"

walker.parentNode();
console.log('parent', walker.currentNode.id); // => "root"

walker.parentNode();
walker.parentNode();
walker.parentNode();
console.log('parent (3x)', walker.currentNode.id); // => "root"

同一のオブジェクト walker を使い続けている点に注目してください。

2 種類の「次」

nextSibling()nextNode() があります。

nextSibling() は同階層で次のノードへ移動します。( sibling は「兄弟姉妹」の意味。) 普通に使うならきっとこちらですね。

対して nextNode() の場合は文書ツリーに出現する順序で次のものを返します。全ノードを走査する場合はこちら。

do {
  console.log(walker.currentNode.id);
} while(walker.nextNode())
// "root"
// "child1"
// "child2"
// "child2-1"
// "child2-2"
// "child2-3"
// "child3"

移動先がない場合は null を返し、currentNode を更新しません。他も同じ。

フィルタリング

第 2 引数でどのノードを対象にするか指定します。

先の例では要素ノードだけでしたが、テキストノードも欲しいときはこう。

const walker = document.createTreeWalker(
  elRoot,
  NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT
);

ビットのフラグなのでビット論理和の演算子 | で繋げます。SHOW_ELEMENT1 つまり 2 進数で 0001(2)SHOW_TEXT40100(2) 、合わせて 0101(2) になります。まあ数字を気にする必要はないけど仕組みはそういうことです。

あとテキストノードはインデントの空白文字列も含むのでそこら辺うまくやってください。

おしまい

使いどころは思いつきませんでした。

参考