日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

JS魔法堂:判断节点位置关系

發(fā)布時間:2025/4/5 javascript 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JS魔法堂:判断节点位置关系 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、前言                          

? 在polyfill?querySelectorAll 和寫彈出窗時都需要判斷兩個節(jié)點間的位置關(guān)系,通過jQuery我們可以輕松搞定,但原生JS呢?下面我將整理各種判斷方法,以供日后查閱。

?

二、祖孫關(guān)系                        

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');

方法一:通過Selection對象

/** 定義判斷祖孫關(guān)系函數(shù)* @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; };// 調(diào)用 console.log(has(ancestor, son)); // 顯示true console.log(has(ancestor, other)); // 顯示false

缺點:僅僅FF支持,其他瀏覽器一律無效

1. 執(zhí)行?selection.selectAllChildren(parentNode)?時,parentNode的內(nèi)容會被高亮,并且原來高亮的部分將被取消;

2. chrome下,?selection.containsNode()恒返回false?;

3. IE9~11下的Selection類型對象沒有containsNode方法;

4. IE5.5~8下沒有Selection類型;

?

關(guān)于IE下的[object Selection]和[object MSSelection]類型(詳細可瀏覽《JS魔法堂:細說Selection和MSSelection類型》)

1. IE11僅有[object Selection]類型

? 獲取方式:?document.getSelection()?或?window.getSelection()?

2. IE9~10有[object MSSelection]和[object Selection]兩種類型

? 獲取[object MSSelection]:?document.selection?

? 獲取[object Selection]:?document.getSelection()?和?window.getSelection()?

3. IE5.5~IE8僅有[object MSSelection]類型

? 獲取方式:?document.selection?

? ? ?注意:document.selection是IE的特有屬性。

?

方法二:通過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; };

缺點:不兼容IE5.5~8(IE9+、FF和Chrome均支持)

1. IE5.5~8沒有?document.createRange()?方法

關(guān)于[object Range]、[object TextRange]和[object ControlRange]類型

? 首先明確的是[object Range]是符合W3C標(biāo)準(zhǔn)的,而[object TextRange]和[object ControlRange]是IE獨有的。

(詳細可瀏覽《JS魔法堂:細說Range、TextRange和ControlRange類型》)

1. 通過document.createRange()創(chuàng)建[object Range]對象

2. 通過window.getSelection().getRangeAt({unsigned int32} index)獲取[object Range]對象

3. 通過document.selection.createRange()或document.selection.createRangeCollection()方法獲取[object TextRange]對象,并且無法像Range對象內(nèi)容通過selectNode方法直接綁定到DOM片段中。

?

方法三:通過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

優(yōu)點:簡單直接

缺點:兼容性問題

支持——chrome、 firefox9+、 ie5+、 opera9.64+(估計從9.0+)、safari5.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可以算是W3C標(biāo)準(zhǔn)中比較兩節(jié)點位置關(guān)系的一大利器,不僅可以判斷祖孫關(guān)系,還可以判斷其他關(guān)系哦?

var ret = A.compareDocumentPosition(B);

返回值ret的意思如下:

? Bits????????? Number??????? Meaning?
000000???????? 0????????????? 元素一致?
000001???????? 1????????????? 節(jié)點在不同的文檔(或者一個在文檔之外)?
000010???????? 2????????????? 節(jié)點 B 在節(jié)點 A 之前?
000100???????? 4????????????? 節(jié)點 A 在節(jié)點 B 之前?
001000???????? 8????????????? 節(jié)點 B 包含節(jié)點 A?
010000???????? 16???????????? 節(jié)點 A 包含節(jié)點 B?
100000???????? 32???????????? 瀏覽器的私有使用

?

方法五:遞歸遍歷

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;} }

優(yōu)點:所有瀏覽器均通用

缺點:當(dāng)節(jié)點層級深時,效率較低。

?

綜合方案一,來自司徒正美(http://m.cnblogs.com/57731/1583523.html?full=1):

//2013.1.24 by 司徒正美
function contains(parentEl, el, container) {// 第一個節(jié)點是否包含第二個節(jié)點//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;}

綜合方案二,來自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;
};

?

?三、總結(jié)                              

? 尊重原創(chuàng),轉(zhuǎn)載請注明來自:http://www.cnblogs.com/fsjohnhuang/p/3931818.html^_^肥子John

總結(jié)

以上是生活随笔為你收集整理的JS魔法堂:判断节点位置关系的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。