这篇文章发布于 2019年03月2日,星期六,20:52,归类于 JS API。 阅读 18819 次, 今日 17 次 7 条评论
by zhangxinxu 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
(本篇完)
- 深入Node.compareDocumentPosition API (0.722)
- DOM基础小测27期答疑文字版-窗体滚动二三事 (0.320)
- 粉丝群第1期CSS小测点评与答疑 (0.278)
- 粉丝群第27期JS基础小测答疑文字版 (0.278)
- DOMParser和XMLSerializer两个API简介 (0.165)
- 小tips: JS DOM innerText和textContent的区别 (0.165)
- 小tip:我是如何初体验uglifyjs压缩JS的 (0.124)
- JS一般般的网页重构可以使用Node.js做些什么 (0.124)
- 使用electron构建跨平台Node.js桌面应用经验分享 (0.124)
- 我是如何实现electron的在线升级热更新功能的? (0.124)
- HTML5 DOM元素类名相关操作API classList简介 (RANDOM - 0.041)
学到了~
学习了
日常支持大佬
学习了,感谢鑫神
想进群~
每周六上午10:00~11:00之间的直播上哪里去看
点个赞