再谈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 相关文章推荐
基于jQuery的合并表格中相同文本的相邻单元格的代码
Apr 06 Javascript
基于JQuery的动态删除Table表格的行和列的代码
May 12 Javascript
jQuery学习笔记之控制页面实现代码
Feb 27 Javascript
javascript简单实现命名空间效果
Mar 06 Javascript
使用原生js封装webapp滑动效果(惯性滑动、滑动回弹)
May 06 Javascript
JS合并数组的几种方法及优劣比较
Sep 19 Javascript
js实现四舍五入完全保留两位小数的方法
Aug 02 Javascript
微信小程序 倒计时组件实现代码
Oct 24 Javascript
原生JS实现的跳一跳小游戏完整实例
Jan 27 Javascript
jQuery实现动态添加和删除input框实例代码
Mar 26 jQuery
vue中的面包屑导航组件实例代码
Jul 01 Javascript
Vue+axios封装请求实现前后端分离
Oct 23 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
Ajax PHP简单入门教程代码
2008/04/25 PHP
php 无限级 SelectTree 类
2009/05/19 PHP
MayFish PHP的MVC架构的开发框架
2009/08/13 PHP
什么情况下可以不写PHP的闭合标签“?&gt;”
2014/08/28 PHP
PHP将session信息存储到数据库的类实例
2015/03/04 PHP
php实现二叉树中和为某一值的路径方法
2018/10/14 PHP
jQuery 版元素拖拽原型代码
2011/04/25 Javascript
jQuery自定义事件的简单实现代码
2014/01/27 Javascript
js与运算符和或运算符的妙用
2014/02/14 Javascript
js中函数调用的两种常用方法使用介绍
2014/07/17 Javascript
JavaScript实现图片轮播的方法
2015/07/31 Javascript
浅谈jquery中的each方法$.each、this.each、$.fn.each
2016/06/23 Javascript
使用jQuery的toggle()方法对HTML标签进行显示、隐藏的方法(示例)
2016/09/01 Javascript
详解如何在Vue里建立长按指令
2018/08/20 Javascript
vue 项目地址去掉 #的方法
2018/10/20 Javascript
vue.js层叠轮播效果的实例代码
2018/11/08 Javascript
jQuery实现当拉动滚动条到底部加载数据的方法分析
2019/01/24 jQuery
Node.js从字符串生成文件流的实现方法
2019/08/18 Javascript
使用vue实现多规格选择实例(SKU)
2019/08/23 Javascript
一起写一个即插即用的Vue Loading插件实现
2019/10/31 Javascript
ES6扩展运算符和rest运算符用法实例分析
2020/05/23 Javascript
JS实现拖拽元素时与另一元素碰撞检测
2020/08/27 Javascript
[51:06]2018DOTA2亚洲邀请赛3月29日 小组赛A组 KG VS Liquid
2018/03/30 DOTA
详解Python中的Descriptor描述符类
2016/06/14 Python
Python爬虫DOTA排行榜爬取实例(分享)
2017/06/13 Python
python获取多线程及子线程的返回值
2017/11/15 Python
pymongo中group by的操作方法教程
2019/03/22 Python
浅谈django channels 路由误导
2020/05/28 Python
Canvas在超级玛丽游戏中的应用详解
2021/02/06 HTML / CSS
瑞士香水购物网站:Parfumcity.ch
2017/01/14 全球购物
美津浓巴西官方网站:Mizuno巴西
2019/07/24 全球购物
麦当劳印度网上订餐:McDelivery
2020/03/16 全球购物
建筑专业毕业生求职信
2014/09/30 职场文书
大学校园招聘会感想
2015/08/10 职场文书
Rust 连接 PostgreSQL 数据库的详细过程
2022/01/22 PostgreSQL
Python接口自动化之文件上传/下载接口详解
2022/04/05 Python