DOMおれおれAdvent Calendar 2015 – 16日目

2015-12-16

HTMLが以下のような構成だとして、 #origin を起点に各要素との位置を比較してみます。

compareTargetTree
入れ子になった要素群。

var origin = document.querySelector('#origin');
var parent = document.querySelector('#parent');

var result = origin.compareDocumentPosition(parent);
console.log(!!(result & origin.DOCUMENT_POSITION_PRECEDING));     // => true
console.log(!!(result & origin.DOCUMENT_POSITION_FOLLOWING));     // => false
console.log(!!(result & origin.DOCUMENT_POSITION_CONTAINS));      // => true
console.log(!!(result & origin.DOCUMENT_POSITION_CONTAINED_BY));  // => false
console.log(!!(result & origin.DOCUMENT_POSITION_DISCONNECTED));  // => false

状態

node.DOCUMENT_POSITION_CONTAINS みたいな感じで定義されています。

状態 定数
#origin から見て先 DOCUMENT_POSITION_PRECEDING
#origin から見て後 DOCUMENT_POSITION_FOLLOWING
#origin から見て上 DOCUMENT_POSITION_CONTAINS
#origin から見て下 DOCUMENT_POSITION_CONTAINED_BY
#origin とは無関係 DOCUMENT_POSITION_DISCONNECTED

前後関係はツリーを順々に見て行った場合のものになるので、兄弟でなくてもPRECEDINGないしFOLLOWINGになります。

無関係と判断されるのは所属するドキュメントツリー自体が別の場合ですかね。ノード生成の後、まだツリーに追加していない場合とか。

上記の他に、ブラウザーが独自に拡張できる値も用意されてるみたいです。

比較は && ではなく &

ビット演算子です。演算子の説明はしませんが、この仕組みのおかげで複数の状態を同時に持つ事ができます。

var result = origin.compareDocumentPosition(el);
if (result & el.DOCUMENT_POSITION_FOLLOWING) {
  console.log('elが先に出てきます。');
}
if (result & el.DOCUMENT_POSITION_CONTAINS) {  // <-else ifじゃない
  console.log('elに含まれてます。');
}

諸々を確認した結果

compareTargetTree
入れ子になった要素群。(再掲)

vs ancestor
 - PRECEDING
 - CONTAINS
vs parent
 - PRECEDING
 - CONTAINS
vs elder
 - PRECEDING
vs elder-child
 - PRECEDING
vs younger
 - FOLLOWING
vs child
 - FOLLOWING
 - CONTAINED_BY
vs descendant
 - FOLLOWING
 - CONTAINED_BY
vs younger-anscestor
 - FOLLOWING

contains()

要素を含むかどうかだけなら origin.contains(target) というAPIもあります。

環境

IE 9+。他は大丈夫そうです。

参考