DOM小測28期 – DOM節點文件前後位置判斷
byzhangxinxu from https://www.zhangxinxu.com/wordpress/?p=8522
本文可全文轉載,個人網站無需授權,只要保留原作者、出處以及文中連結即可,任何網站均可摘要聚合,商用請聯絡授權。
一、題目與考察點
題目地址: https://github.com/zhangxinxu/quiz/issues/9
題目內容如下(點選檢視大圖):
本題主要考察如何判斷DOM節點文件前後位置,父子關係等。我看了下最後的回答,近9成的回答使用了非常囉嗦的方法,比例之高,實在出乎意料。實際上,本題有非常簡單、寥寥數行就能實現的方法,只要你知道下面這兩個很有用的DOM原生API,一個是 contains()
方法,判斷DOM元素或節點是否有包含關係;另外一個是 compareDocumentPosition()
方法,更強悍的DOM或節點位置關係判斷,無論是前後、內外還是跨文件都可以。
本次B站答疑直播在上午10:34分開始,持續約30分鐘,有錄播,可以直接點選下面的視訊觀看。
二、DOM包含關係判斷contains()
contains()
方法是一個很古老的API,用來判斷兩個DOM節點之間的包含關係,語法如下:
node.contains(otherNode)
返回布林值,表示 node
是否包含 otherNode
,或者就是 node
本身。
例如:
document.documentElement.contains(document.body);// 返回值是true document.body.contains(document.body);// 返回值是true document.body.contains(document.documentElement);// 返回值是false
此API相容性良好,IE5就開始支援了,使用非常方便,我們無需專門遍歷祖先元素用判斷兩個節點之間的巢狀關係。
其它
如果判斷的兩個節點元素是跨iframe文件的,則會被認為是 false
。例如我們直接 藉助Blob動態建立一個非外鏈iframe ,程式碼如下:
var htmlIframe = '<img id="img" src="https://.../mm.jpg" onclick="console.log(window.parent.document.body.contains(this))">'; var iframe = document.createElement('iframe'); var blob = new Blob([htmlIframe], { 'type': 'text/html'}); iframe.src = URL.createObjectURL(blob); iframeBlob1.appendChild(iframe);
實時效果如下,點選妹子圖片,看看輸出的結果是?
控制檯輸出結果如下:
如果想要知道iframe內外的包含關係,則需要使用另外的API: compareDocumentPosition()
。
三、任意位置判斷compareDocumentPosition
本題中圖片DOM元素前後位置的比對完全不需要寫迴圈進行遍歷,有現成的API可以實現我們想要的效果,那就是 Node.compareDocumentPosition
API。
此API頗有深度,我專門寫了篇文章介紹這個API,可參見這裡:“ 深入Node.compareDocumentPosition API ”。
例如:
var compareValue = img.compareDocumentPosition(compareImg); if (compareValue == 2) { // compareImg在前 } else if (compareValue == 4) { // compareImg在後 } else if (compareValue == 0) { // 就是compareImg元素自身 } else { // 其它位置關係 }
如果 compareValue
是 2
,則表示 compareImg
在 img
的前面;如果是 4
,則表示 compareImg
在 img
的後面。
由此我們可以輕鬆判斷點選圖片和對比圖片之間的文件位置關係,寥寥幾行程式碼的事情。
不過需要注意的是,如果是判斷其他非替換元素的位置關係,則不能使用數值比對,因為可能 compareDocumentPosition()
方法執行後的值是一個混合數值,例如:
// 返回值是 10,8 + 2 document.body.compareDocumentPosition(document.documentElement); // 返回值是 20,16 + 4 document.documentElement.compareDocumentPosition(document.body)
我們需要使用單個 &
符合和對應目標值進行與位運算的結果來判定,例如:
if (document.body.compareDocumentPosition(document.documentElement) & 2) { // document.documentElement在document.body前面 // ... }
如果不是很理解,可以訪問我剛寫的專門 深入介紹compareDocumentPosition 的文章。
四、如何判斷click元素是圖片
例如:
container.onclick = function (event) { // event.target ... }
業界用的比較多的方法是使用tagName值進行判斷,如下:
event.target.tagName == 'IMG'// true或false
所有瀏覽器都返回大寫標籤名,當然,如果你不放心(以後變了,或者遇到SB瀏覽器),可以更嚴格比對下:
/^img$/i.test(event.target.tagName)// true或false
event.target.tagName.toLowerCase() == 'img'// true或false
我們還可以使用nodeName進行判斷,例如:
event.target.nodeName == 'IMG'// true或false
最後,在介紹一種物件型別判斷方法,如下:
event.target instanceof Image// true或false
也是可以的。
五、答疑要點總結
- 包含關係推薦使用
Node.contains()
方法; - 判斷當前元素是否是IMG,可以 :
event.target.tagName/nodeName == 'IMG'
/^img$/i.test(event.target.tagName)
event.target.tagName.toLowerCase() == 'img'
event.target instanceof Image
- 前後節點關係判斷使用
Node.compareDocumentPosition()
。
關於直播答疑
每週三會在這個 專案 的 issues 中釋出小測題,依次CSS,JS和DOM,每週六上午10:00~11:00之間直播答疑。
有興趣參與的可以多多關注下。
以上~
本文為原創文章,會經常更新知識點以及修正一些錯誤,因此轉載請保留原出處,方便溯源,避免陳舊錯誤知識的誤導,同時有更好的閱讀體驗。
本文地址: https://www.zhangxinxu.com/wordpress/?p=8522
(本篇完)