再谈querySelector和querySelectorAll的区别与联系


Posted in Javascript onApril 20, 2012

先按W3C的规范来说这两个方法应该返回的内容吧:
querySelector:

return the first matching Element node within the node's subtrees. If there is no such node, the method must return null.(返回指定元素节点的子树中匹配selector的集合中的第一个,如果没有匹配,返回null)

querySelectorAll:

return a NodeList containing all of the matching Element nodes within the node's subtrees, in document order. If there are no such nodes, the method must return an empty NodeList. (返回指定元素节点的子树中匹配selector的节点集合,采用的是深度优先预查找;如果没有匹配的,这个方法返回空集合)

使用方法:

var element = baseElement.querySelector(selectors); 
var elementList = baseElement.querySelectorAll(selectors);

这在BaseElement 为document的时候,没有什么问题,各浏览器的实现基本一致;但是,当BaseElement 为一个普通的dom Node的时候(支持这两个方法的dom Node),浏览器的实现就有点奇怪了,举个例子:
<div class="test" id="testId"> 
<p><span>Test</span></p> 
</div> 
<script type="text/javascript"> 
var testElement= document.getElementById('testId'); 
var element = testElement.querySelector('.test span'); 
var elementList = document.querySelectorAll('.test span'); 
console.log(element); // <span>Test</span> 
console.log(elementList); // 1 
</script>

按照W3C的来理解,这个例子应该返回:element:null;elementList:[];因为作为baseElement的 testElement里面根本没有符合selectors的匹配子节点;但浏览器却好像无视了baseElement,只在乎selectors,也就是说此时baseElement近乎document;这和我们的预期结果不合,也许随着浏览器的不断升级,这个问题会得到统一口径!
人的智慧总是无穷的,Andrew Dupont发明了一种方法暂时修正了这个怪问题,就是在selectors前面指定baseElement的id,限制匹配的范围;这个方法被广泛的应用在各大流行框架中;
Jquery的实现:
var oldContext = context, 
old = context.getAttribute( "id" ),<BR> nid = old || id, 
try { 
if ( !relativeHierarchySelector || hasParent ) { 
return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); 
} 
} catch(pseudoError) {} <BR>finally { 
if ( !old ) {oldContext.removeAttribute( "id" );} 
}

先不看这点代码中其他的地方,只看他如何实现这个方法的;这点代码是JQuery1.6的片段;当baseElement没有ID的时候,给他设置一个id = "__sizzle__”,然后再使用的时候加在selectors的前面,做到范围限制;context.querySelectorAll( "[id='" + nid + "'] " + query ;最后,因为这个ID本身不是baseElement应该有的,所以,还需要移除:oldContext.removeAttribute( "id" );
,Mootools的实现:
var currentId = _context.getAttribute('id'), slickid = 'slickid__'; 
_context.setAttribute('id', slickid); 
_expression = '#' + slickid + ' ' + _expression; 
context = _context.parentNode;

Mootools和Jquery类似:只不过slickid = 'slickid__';其实意义是一样的;

方法兼容性:FF3.5+/IE8+/Chrome 1+/opera 10+/Safari 3.2+;

IE 8 :不支持baseElement为object;

非常感谢大牛JK的回复,提供了另外一种方法。

Javascript 相关文章推荐
filemanage功能中用到的common.js
Apr 08 Javascript
正则表达式判断是否存在中文和全角字符和判断包含中文字符串长度
Sep 27 Javascript
Javascript 调试利器 Firebug使用详解六
Jul 05 Javascript
JS中confirm,alert,prompt函数区别分析
Jan 17 Javascript
file模式访问网页时iframe高度自适应解决方案
Jan 16 Javascript
JavaScript将数字转换成大写中文的方法
Mar 23 Javascript
Vue2.0表单校验组件vee-validate的使用详解
May 02 Javascript
vue2.0实现前端星星评分功能组件实例代码
Feb 12 Javascript
浅谈vue后台管理系统权限控制思考与实践
Dec 19 Javascript
解决IOS端微信H5页面软键盘弹起后页面下方留白的问题
Jun 05 Javascript
Vue + Elementui实现多标签页共存的方法
Jun 12 Javascript
layer页面跳转,获取html子节点元素的值方法
Sep 27 Javascript
js querySelector和getElementById通过id获取元素的区别
Apr 20 #Javascript
仿微博字符限制效果实现代码
Apr 20 #Javascript
javascript 另一种图片滚动切换效果思路
Apr 20 #Javascript
分享一个自定义的console类 让你不再纠结JS中的调试代码的兼容
Apr 20 #Javascript
浏览器解析js生成的html出现样式问题的解决方法
Apr 16 #Javascript
基于jquery的不规则矩形的排列实现代码
Apr 16 #Javascript
JavaScript打开word文档的实现代码(c#)
Apr 16 #Javascript
You might like
一步一步学习PHP(2)――PHP类型
2010/02/15 PHP
ThinkPHP模板引擎之导入资源文件方法详解
2014/06/18 PHP
php将字符串全部转换成大写或者小写的方法
2015/03/17 PHP
解决ThinkPHP关闭调试模式时报错的问题汇总
2015/04/22 PHP
Yii2实现多域名跨域同步登录退出
2017/02/04 PHP
Laravel Intervention/image图片处理扩展包的安装、使用与可能遇到的坑详解
2017/11/14 PHP
php插入mysql数据返回id的方法
2018/05/31 PHP
php常用日期时间函数实例小结
2019/07/04 PHP
php post换行的方法
2020/02/03 PHP
浅析jQuery EasyUI中的tree使用指南
2014/12/18 Javascript
js实现Form栏显示全格式时间时钟效果代码
2015/08/19 Javascript
js点击文本框后才加载验证码实例代码
2015/10/20 Javascript
vue.js 使用v-if v-else发现没有执行解决办法
2017/05/15 Javascript
JavaScript中offsetWidth的bug及解决方法
2017/05/17 Javascript
JavaScript 上传文件(psd,压缩包等),图片,视频的实现方法
2017/06/19 Javascript
浅谈React高阶组件
2018/03/28 Javascript
vue中使用element组件时事件想要传递其他参数的问题
2019/09/18 Javascript
[54:45]2018DOTA2亚洲邀请赛 4.1 小组赛 A组 Optic vs OG
2018/04/02 DOTA
python 实现将list转成字符串,中间用空格隔开
2019/12/25 Python
如何在 Django 模板中输出 &quot;{{&quot;
2020/01/24 Python
在pycharm中实现删除bookmark
2020/02/14 Python
基于python 等频分箱qcut问题的解决
2020/03/03 Python
Python API len函数操作过程解析
2020/03/05 Python
Python类和实例的属性机制原理详解
2020/03/21 Python
Django通过设置CORS解决跨域问题
2020/11/26 Python
使用Python+Appuim 清理微信的方法
2021/01/26 Python
Blue Nile台湾:钻石珠宝商,订婚首饰、结婚戒指和精品首饰
2017/11/24 全球购物
PHP如何调用MYSQL存储过程
2014/05/30 面试题
Java中实现多态的机制
2015/08/09 面试题
毕业自我鉴定
2013/11/05 职场文书
检察院院长群众路线教育实践活动个人整改措施
2014/10/04 职场文书
2015年父亲节寄语
2015/03/23 职场文书
我爱我班主题班会
2015/08/13 职场文书
写给汽车4S店的创业计划书,拿来即用!
2019/08/09 职场文书
班干部竞选演讲稿(精选5篇)
2019/09/24 职场文书
js中Object.create实例用法详解
2021/10/05 Javascript