JS魔法堂:ノードの位置関係を判断する
15662 ワード
一、前言
polyfill querySelectorAllとポップアップウィンドウを書くときは両方のノード間の位置関係を判断する必要がありますが、jQueryで簡単にできますが、オリジナルJSは?これからいろいろな判断方法を整理して、後日調べることができます.
二、祖先と孫の関係
html
common.js
メソッド1:Selectionオブジェクトを介して
欠点:FFサポートのみ、他のブラウザはすべて無効
1.selectionを実行する.selectAllChildren(parentNode)の場合、parentNodeの内容がハイライトされ、元のハイライトされた部分がキャンセルされます.
2.chromeの下、selection.containsNode()はfalseを一定に返します.
3.IE 9~11の下のSelectionタイプオブジェクトにはcontainsNodeメソッドがない.
4. IE5.5~8でSelectionタイプはありません.
IE下の「object Selection」と「object MSSelection」タイプについて(詳細は『JS魔法堂:詳しくはSelectionとMSSelectionタイプ』参照)
1.IE 11は[object Selection]タイプのみ
取得方法:document.getSelection()またはwindow.getSelection()
2.IE 9~10は[object MSSelection]と[object Selection]の2種類がある
取得[object MSSelection]:document.selection
取得[object Selection]:document.getSelection()とwindow.getSelection()
3. IE5.5~IE 8は[object MSSelection]タイプのみ
取得方法:document.selection
注意:document.selectionはIE特有の属性です.
メソッド2:Rangeオブジェクトによる
欠点:IE 5と互換性がない.5~8(IE 9+、FF、Chromeともにサポート)
1. IE5.5~8 documentなし.createRange()メソッド
[object Range]、[object TextRange]、および[object Control Range]タイプについて
まず、「object Range」はW 3 C規格に準拠しており、「object TextRange」と「objectControlRange」はIE独自であることが明らかになった.
(詳しくは『JS魔法堂:Range、TextRange、ControlRangeタイプ』参照)
1.document.createRange()[object Range]オブジェクトの作成
2.Windows経由getSelection().getRangeAt({unsigned int 32}index)[object Range]オブジェクトを取得
3.document.selection.牙列缺损selection.createRangeCollection()メソッドは[object TextRange]オブジェクトを取得し、Rangeオブジェクトの内容のようにselectNodeメソッドで直接DOMクリップにバインドすることはできません.
方法3:containsメソッドによる
メリット:シンプルでストレート
短所:互換性の問題
サポート-chrome、firefox 9+、ie 5+、opera 9.64+(推定9.0+)、safari 5.1.7+
サポートしない——FF
方法四:compareDocumentPositionによる方法
compareDocumentPositionはW 3 C基準で両ノードの位置関係を比較する大きな利器と言えるので、祖父母と孫の関係だけでなく、他の関係も判断できますよ
var ret = A.compareDocumentPosition(B);
戻り値retの意味は次のとおりです.
Bits Number Meaning 00000要素が一致する000001ノードは、異なるドキュメント(またはドキュメントの外)にあります.0000102ノードBノードAより前0001004ノードAノードBより前001008ノードBノードA 010000 16ノードAノードB 100000 32ブラウザのプライベート使用
方法5:再帰遍歴
利点:すべてのブラウザで共通
欠点:ノードレベルが深い場合、効率が低下します.
総合案1は司徒正美(http://m.cnblogs.com/57731/1583523.html?full=1):
総合案2、Sizzle(https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L688)
注意:Sizzleのcontainsバージョンはcontains(ancestor,ancestor)がfalseを返します.
総合案三、私のあの長くて臭いバージョン^^;
三、まとめ
オリジナルを尊重し、転載は以下のことを明記してください.http://www.cnblogs.com/fsjohnhuang/p/3931818.html^_^肥えたジョン
polyfill querySelectorAllとポップアップウィンドウを書くときは両方のノード間の位置関係を判断する必要がありますが、jQueryで簡単にできますが、オリジナルJSは?これからいろいろな判断方法を整理して、後日調べることができます.
二、祖先と孫の関係
html
<div id="ancestor">
<div id="parent">
<div id="son">son</div>
</div>
</div>
<div id="other">other</div>
common.js
var ancestor = document.getElementById('ancestor');
var parent = document.getElementById('parent');
var son = document.getElementById('son');
var other = document.getElementById('other');
メソッド1:Selectionオブジェクトを介して
/**
* @param {HTMLElement} parentNode
* @param {HTMLElement} sonNode
*/
var has = function(parentNode, sonNode){
if (parentNode === sonNode) return true;
var selection = window.getSelection();
selection.selectAllChildren(parentNode);
var ret = selection.containsNode(sonNode, false);
return ret;
};
//
console.log(has(ancestor, son)); // true
console.log(has(ancestor, other)); // false
欠点:FFサポートのみ、他のブラウザはすべて無効
1.selectionを実行する.selectAllChildren(parentNode)の場合、parentNodeの内容がハイライトされ、元のハイライトされた部分がキャンセルされます.
2.chromeの下、selection.containsNode()はfalseを一定に返します.
3.IE 9~11の下のSelectionタイプオブジェクトにはcontainsNodeメソッドがない.
4. IE5.5~8でSelectionタイプはありません.
IE下の「object Selection」と「object MSSelection」タイプについて(詳細は『JS魔法堂:詳しくはSelectionとMSSelectionタイプ』参照)
1.IE 11は[object Selection]タイプのみ
取得方法:document.getSelection()またはwindow.getSelection()
2.IE 9~10は[object MSSelection]と[object Selection]の2種類がある
取得[object MSSelection]:document.selection
取得[object Selection]:document.getSelection()とwindow.getSelection()
3. IE5.5~IE 8は[object MSSelection]タイプのみ
取得方法:document.selection
注意:document.selectionはIE特有の属性です.
メソッド2:Rangeオブジェクトによる
var has = function(parentNode, sonNode){
if (parentNode === sonNode) return true;
var r1 = document.createRange(), r2 = document.createRange();
r1.selectNode(parentNode);
r2.selectNode(sonNode);
var startRet = r1.compareBoundaryPoints(Range.START_TO_START, r2);
var endRet = r1.compareBOundaryPoints(Range.END_TO_END, r2);
var ret = startRet === -1 && endRet === 1;
return ret;
};
欠点:IE 5と互換性がない.5~8(IE 9+、FF、Chromeともにサポート)
1. IE5.5~8 documentなし.createRange()メソッド
[object Range]、[object TextRange]、および[object Control Range]タイプについて
まず、「object Range」はW 3 C規格に準拠しており、「object TextRange」と「objectControlRange」はIE独自であることが明らかになった.
(詳しくは『JS魔法堂:Range、TextRange、ControlRangeタイプ』参照)
1.document.createRange()[object Range]オブジェクトの作成
2.Windows経由getSelection().getRangeAt({unsigned int 32}index)[object Range]オブジェクトを取得
3.document.selection.牙列缺损selection.createRangeCollection()メソッドは[object TextRange]オブジェクトを取得し、Rangeオブジェクトの内容のようにselectNodeメソッドで直接DOMクリップにバインドすることはできません.
方法3:containsメソッドによる
var has = function(parentNode, sonNode){
return parentNode.contains(sonNode);
};
console.log(has(ancestor, ancestor));// true
console.log(has(ancestor, son));// true
console.log(has(ancestor, other));// false
メリット:シンプルでストレート
短所:互換性の問題
サポート-chrome、firefox 9+、ie 5+、opera 9.64+(推定9.0+)、safari 5.1.7+
サポートしない——FF
方法四:compareDocumentPositionによる方法
var has = function(parentNode, sonNode){
if (parentNode === sonNode) return true;
var rawRet = parentNode.compareDocumentPosition(sonNode);
var ret = !!(rawRet & 16);
return ret;
};
compareDocumentPositionはW 3 C基準で両ノードの位置関係を比較する大きな利器と言えるので、祖父母と孫の関係だけでなく、他の関係も判断できますよ
var ret = A.compareDocumentPosition(B);
戻り値retの意味は次のとおりです.
Bits Number Meaning 00000要素が一致する000001ノードは、異なるドキュメント(またはドキュメントの外)にあります.0000102ノードBノードAより前0001004ノードAノードBより前001008ノードBノードA 010000 16ノードAノードB 100000 32ブラウザのプライベート使用
方法5:再帰遍歴
var has = function(parentNode, sonNode){
if (parentNode === sonNode) return true;
var p = sonNode.parentNode;
if (!p.ownerDocument){
return false;
}
else if (p !== parentNode){
return has(parentNode, p);
}
else{
return true;
}
}
利点:すべてのブラウザで共通
欠点:ノードレベルが深い場合、効率が低下します.
総合案1は司徒正美(http://m.cnblogs.com/57731/1583523.html?full=1):
//2013.1.24 by
function contains(parentEl, el, container) {
//
//contains :chrome+ firefox9+ ie5+, opera9.64+( 9.0+),safari5.1.7+
if (parentEl == el) {
return true;
}
if (!el || !el.nodeType || el.nodeType != 1) {
return false;
}
if (parentEl.contains ) {
return parentEl.contains(el);
}
if ( parentEl.compareDocumentPosition ) {
return !!(parentEl.compareDocumentPosition(el) & 16);
}
var prEl = el.parentNode;
while(prEl && prEl != container) {
if (prEl == parentEl)
return true;
prEl = prEl.parentNode;
}
return false;
}
総合案2、Sizzle(https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L688)
注意:Sizzleのcontainsバージョンはcontains(ancestor,ancestor)がfalseを返します.
// Element contains another
// Purposefully does not implement inclusive descendent
// As in, an element does not contain itself
contains = hasCompare || rnative.test( docElem.contains ) ?
function( a, b ) {
var adown = a.nodeType === 9 ? a.documentElement : a,
bup = b && b.parentNode;
return a === bup || !!( bup && bup.nodeType === 1 && (
adown.contains ?
adown.contains( bup ) :
a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
));
} :
function( a, b ) {
if ( b ) {
while ( (b = b.parentNode) ) {
if ( b === a ) {
return true;
}
}
}
return false;
};
総合案三、私のあの長くて臭いバージョン^^;
var rNative = /[^{]+\{\s*\[native code\]\s*\}/;
var docEl = document.documentElement;
var contains = rNative.test(docEl.contains) && function(ancestor, descendant){
if (ancestor === descendant) return true;
ancestor = ancestor.nodeType === 9 ? ancestor.documentElement : ancestor;
return ancestor.contains(descendant);
} ||
rNative.test(docEl.compareDocumentPosition) &&
function(ancestor, descendant){
if (ancestor === descendant) return true;
ancestor = ancestor.documentElement || ancestor;
return !!(ancestor.compareDocumentPosition(descendant) & 16);
} ||
rNative.test(document.createRange) &&
function(ancestor, descendant){
if (ancestor === descendant) return true;
var r1 = document.createRange(), r2 = document.createRange();
r1.selectNode(ancestor.documentElement || ancestor);
r2.selectNode(descendant.documentElement || descendant);
var startRet = r1.compareBoundaryPoints(Range.START_TO_START, r2); var endRet = r1.compareBOundaryPoints(Range.END_TO_END, r2);
var ret = startRet === -1 && endRet === 1;
try{
r1.detach();
r2.detach();
}catch(e){}
return ret;
} ||
function(ancestor, descendant){
if (ancestor === descendant) return true;
var a = ancestor.documentElement || ancestor;
var b = (descendant.documentElement || descendant)['parentNode'];
while(!!b){
if (a === b) return true;
b = b.parentNode;
}
return false;
};
三、まとめ
オリジナルを尊重し、転載は以下のことを明記してください.http://www.cnblogs.com/fsjohnhuang/p/3931818.html^_^肥えたジョン