这篇文章发布于 2020年12月25日,星期五,00:44,归类于 JS API。 阅读 15099 次, 今日 3 次 9 条评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=9747
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。
JS DOM API中有部分API功能是可以相互替代的,实际上,其是有细节差异的。
说明:本文的这些差异对比均不考虑兼容性差异。
一、innerText对比textContent
这个之前专门写文章介绍过,详见:“JS DOM innerText和textContent的区别”。
大致总结下就是:
innerText
获取的文字的换行符依然保留;innerText
无法获取隐藏文字;innerText
性能要相对差一些;
具体测试可以参见上面那篇文章,这里不再赘述。
二、getAttribute对比dataset对象
例如,有如下HTML:
<button id="button" data-author="zhangxinxu">作者是谁?</button>
使用getAttribute
和dataset
对象都能获取data-author
属性值,例如:
// 结果是:zhangxinxu
button.getAttribute('data-author');
// 结果也是:zhangxinxu
button.dataset.author;
如果您对dataset对象有些陌生,可以参考我差不多10年前写的这篇文章:“HTML5自定义属性对象Dataset简介”。
乍一看,在获取data-*
自定义属性的场景下,getAttribute
和dataset
对象似乎可以等同。
实际上,两者还是有差异的。
差别在于大小写敏感的区别,getAttribute
方法是无视大小写的,例如:
<button id="button" data-AUTHOR="zhangxinxu">作者是谁?</button>
// 结果是:zhangxinxu
button.getAttribute('DATA-author');
// 结果是:undefined
button.dataset.AUTHOR;
截图示意:
在本例中,要想dataset对象正确获取data-AUTHOR
属性值,需要使用小写:
// 结果是:zhangxinxu
button.dataset.author;
如果自定义属性包含多个词组,则dataset对象属性值需要使用驼峰命名获取,例如:
<button id="button" data-article-author="zhangxinxu">感谢阅读!</button>
// 结果都是:zhangxinxu
button.getAttribute('data-article-author');
button.dataset.articleAuthor;
且只能使用驼峰命名方法,例如下面的语句还是返回undefined
:
// 结果是:undefined
button.dataset['article-author'];
运行结果如下图所示:
三、getElementById对比querySelector
已知一个元素的ID是'thanksForShare'
,则下面两行DOM API的使用最后返回的结果是一样的:
// 结果是:true
document.getElementById('thanksForShare') === document.querySelector('#thanksForShare')
Chrome控制台跑一下,结果如下:
这么一看,对于通过ID选择器获取元素上,getElementById
和querySelector
方法似乎是等效的,究竟用哪个直接看心情就好了,是这样的吗?
实际上不是的,推荐使用getElementById()
方法,因为这个API的容错性最强,不容易导致JS运行中断。
假设某个元素的ID是未知的,通过参数传过来的,但是这个字符串参数可能各种各样,假设这个字符串是'thanksForShare!'
,此时分别运行下面的代码:
// 结果是?
document.getElementById('thanksForShare!');
document.querySelector('#thanksForShare!');
结果getElementById()
方法安全地返回了null
,但是querySelector()
方法直接报错了:
VM309:1 Uncaught DOMException: Failed to execute ‘querySelector’ on ‘Document’: ‘#thanksForShare!’ is not a valid selector.
眼见为实,特意run了下给大家看:
也就是说,在使用querySelector()
方法的时候,我们需要对里面的选择器进行合法性校验,或者try…catch处理,否则就会影响整个JavaScript代码的运行。
麻烦!
因此,如果条件可以,优先使用getElementById()
方法去获取DOM元素。
//zxx: 如果你看到这段文字,说明你现在访问是体验糟糕的垃圾盗版网站,你可以访问原文获得很好的体验:https://www.zhangxinxu.com/wordpress/?p=9747(作者张鑫旭)
四、append对比appendChild
append()
API方法以前其实也介绍过,和很多API在一起介绍的,大家可能没注意,这里再讲下。
对于节点,append
和appendChild
功能基本是一致的。
例如:
let div = document.createElement('div'); div.content = '欢迎分享到你的朋友圈'; // 下面两行作用一样的 document.body.append(div); // 等同于 document.body.appendChild(div);
都能在元素的后面添加DOM节点元素,包括文本节点,注释节点,元素等都可以。
区别在于下面:
append()
方法可以一次append多个元素,例如:dom.append(node1, node2, node3, ...)
appendChild
方法只能一次append一个元素。append()
方法还可以append
字符串(会自动HTML转义)。例如:document.body.append('', '');
最后页面上出现的不是图片,而是相关的转义后的HTML字符串,如下所示:
五、scrollIntoView对比scrollIntoViewIfNeeded
scrollIntoView
和scrollIntoViewIfNeeded
方法的区别主要2点:
- 行为上的区别
如果元素已经在视区了,则scrollIntoViewIfNeeded()
方法执行的时候,页面是不会滚动定位的。 - 语法上的区别
scrollIntoView()
支持设置滚动定位的时候是否是平滑滚动,参数是smooth,详见我的这篇文章“CSS scroll-behavior和JS scrollIntoView让页面滚动平滑”。scrollIntoViewIfNeeded()
的滚动定位只能是硬邦邦的效果。以及
scrollIntoView()
支持精准设置定位的元素是定位到视区的上方、下方还是中间,语法参数使用示意如下:element.scrollIntoView({ // 还支持start和end值 block: 'center', // 平滑滚动 behavior: 'smooth' });
而
scrollIntoViewIfNeeded()
的定位位置就比较粗糙,无法精确,只支持一个Boolean参数值,true表示居中,false表示或上边缘或下边缘。// 视区居中定位 element.scrollIntoViewIfNeeded(true); // 视区上边缘或下边缘滚动定位 element.scrollIntoViewIfNeeded(false);
大部分情况下,这两个方法是可以互相替换使用的。
六、结语
当然,还有很多其他功能可以互相替代,但是实际上有细节差异的DOM API,欢迎补充,我会及时更新。
感谢您的阅读,如果您觉得本文内容还不错,欢迎分享,让更多的小伙伴知道。
最后祝大家圣诞节快乐,马瑞亏瑞美思,笑口常开,^_^
本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=9747
(本篇完)
- 小tips: JS DOM innerText和textContent的区别 (0.344)
- HTML5自定义属性对象Dataset简介 (0.255)
- DOM元素querySelectorAll可能让你意外的特性表现 (0.235)
- HTML全局属性列表大全 (0.146)
- before(),after(),prepend(),append()等新DOM方法简介 (0.126)
- jquery之append与insertBefore使用实例 (0.109)
- 获取元素CSS值之getComputedStyle方法熟悉 (0.109)
- 原来DOM还有toggleAttribute这样的JS API (0.109)
- 巧用DOM API实现HTML字符的转义和反转义 (0.109)
- gitee上撸了个类似飞书OKR输入框的@提及项目 (0.109)
- jQuery之addClasas与removeClass使用实例 (RANDOM - 0.016)
对比着用,不错!!
分享一下我测试的兼容性:
document.body.append , IE11- 不支持
dataset对象, IE10- 不支持
我認為這是歷史遺留下來的問題,這幾個相似的 API 都應該合併,再用 API 參數的方式得到不同的行為。
getElementBy*、querySelector*类API最核心的差异是前者是动态实时(会自动包含实时动态插入的新元素),后者只是一个静态快照(只包含调用Api那个时刻匹配的元素,不包含新建的)。
赞!
没错,补充一下:
getElementsByTagName / getElementsByClassName 返回值类型是 [object HTMLCollection]
querySelectorAll 返回值类型是 [object NodeList]
学到了?
我有点没理解,
我新建一个元素,用querySelector拿到该元素,再往这个元素内添加另一个子元素。之后输出 innerHtml 发现也包含新插入的元素?
let body = document.body;
let test = create(‘test’)
body.append(test);
let byId = document.getElementById(‘test’);
let byQuery = document.querySelector(‘#test’);
test.append(create(‘sub’));
console.log(byId.innerHTML); // 输出
console.log(byQuery.innerHTML); // 输出
function create(id) {
let div = document.createElement(‘div’);
div.id = id
return div;
}
cool