原生的强大DOM选择器querySelector介绍_基础知识

在传统的 JavaScript 开发中,查找 DOM 往往是开发人员遇到的第一个头疼的问题,原生的 JavaScript 所提供的 DOM 选择方法并不多,仅仅局限于通过 tag, name, id 等方式来查找,这显然是远远不够的,如果想要进行更为精确的选择不得不使用看起来非常繁琐的正则表达式,或者使用某个库。事实上,现在所有的浏览器厂商都提供了 querySelector 和 querySelectorAll 这两个方法的支持,甚至就连微软也派出了 IE 8 作为支持这一特性的代表,querySelector 和 querySelectorAll 作为查找 DOM 的又一途径,极大地方便了开发者,使用它们,你可以像使用 CSS 选择器一样快速地查找到你需要的节点。

querySelector 和 querySelectorAll 的使用非常的简单,就像标题说到的一样,它和 CSS 的写法完全一样,对于前端开发人员来说,这是难度几乎为零的一次学习。假如我们有一个 id 为 test 的 DIV,为了获取到这个元素,你也许会像下面这样:

document.getElementById("test");
现在我们来试试使用新方法来获取这个 DIV:

document.querySelector("#test");
document.querySelectorAll("#test")[0];

下面是个小演示:

我是 id 为 test 的 div

感觉区别不大是吧,但如果是稍微复杂点的情况,原始的方法将变得非常麻烦,这时候 querySelector 和 querySelectorAll 的优势就发挥出来了。比如接下来这个例子,我们将在 document 中选取 class 为 test 的 div 的子元素 p 的第一个子元素,当然这很拗口,但是用本文的新方法来选择这个元素,比用言语来描述它还要简单。

document.querySelector("div.test>p:first-child");
document.querySelectorAll("div.test>p:first-child")[0];

下面是个小演示:

我是层里的 p 标签

现在应该对于 querySelector、querySelectorAll 方法中的参数已经非常明白了,是的,它接收的参数和 CSS 选择器完全一致。querySelector 和 querySelectorAll 的区别在于 querySelector 用来获取一个元素,而querySelectorAll 可以获取多个元素。querySelector 将返回匹配到的第一个元素,如果没有匹配的元素则返回 Null。querySelectorAll 返回一个包含匹配到的元素的数组,如果没有匹配的元素则返回的数组为空。在本文最后一个例子中,我们使用 querySelectorAll 给所有 class 为 emphasis 的元素加粗显示。

var emphasisText = document.querySelectorAll(".emphasis");
for( var i = 0 , j = emphasisText.length ; i < j ; i++ ){
  emphasisText[i].style.fontWeight = "bold";
}

这是原生方法,比起jquery速度快,缺点是IE6、7不支持。

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的节点集合,采用的是深度优先预查找;如果没有匹配的,这个方法返回空集合)

这在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"  ),
nid = old || id,
try  {
	if  ( !relativeHierarchySelector || hasParent ) {
   	return  makeArray( context.querySelectorAll( "[id='"  + nid + "'] "  + query ), extra );
 	}
}
catch (pseudoError) {}
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;

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索querySelector
queryselector 选择器、dom queryselector、selector选择器、js selector选择器、html 选择器 selector,以便于您获取更多的相关知识。

时间: 2024-10-25 06:43:01

原生的强大DOM选择器querySelector介绍_基础知识的相关文章

js选择器全面解析_基础知识

原生JS选择器有getElementById.getElementsByName.getElementsByTagName和getElementsByClassName这四个,下面我就一个一个介绍这四个选择器的用法. 1.getElementById(通过ID获取元素) 用法:document.getElementById("Id");Id为要获取的元素的id属性值. 2.getElementsByName(通过name属性获取元素) 用法:document.getElementsBy

js闭包引起的事件注册问题介绍_基础知识

背景:闲暇时间看了几篇关于js作用域链与闭包的文章,偶然又看到了之前遇到的一个问题,就是在for循环中为dom节点注册事件驱动,具体见下面代码: <!DOCTYPE html> <html> <head> <title>js闭包</title> <meta charset="utf-8" /> </head> <body> <button id="anchor1"&

JS中的this变量的使用介绍_基础知识

JavaScript中this的使用 在JavaScript中this变量是一个令人难以摸清的关键字,this可谓是非常强大,充分了解this的相关知识有助于我们在编写面向对象的JavaScript程序时能够游刃有余. 对于this变量最要的是能够理清this所引用的对象到底是哪一个,也许很多资料上都有自己的解释,但有些概念讲的偏繁杂.而我的理解是:首先分析this所在的函数是当做哪个对象的方法调用的,则该对象就是this所引用的对象. 示例一. 复制代码 代码如下: var obj = {};

浅析JS操作DOM的一些常用方法_基础知识

getElementById(): 获取有指定惟一ID属性值文档中的元素 getElementsByName(name): 返回的是数组 getElementsByTagName(): 返回具有指定标签名的元素子元素集合 getAttribute(): 返回指定属性名的属性值 document.getElementsByTagName("a")[0].getAttribute("target"); setAttribute(): 添加指定的属性,并为其赋指定的值.

Javascript数组Array基础介绍_基础知识

Javascript,一门神奇的语言,它的数组也同样独特.我们要去其糟粕,取其精华,把常用的最优实践总结出来.如有错误,请指出. javascript数组是一种类数组的对象,拥有对象的特性.当属性名是小而连续的整数时,应该使用数组,否则,使用对象. 数组来源 所有的数组都是Array构造出来的,我们来测试一下constructor这个属性. var arr = []; arr.constructor === Array; // true arr.constructor === Array.pro

AngularJS 指令详细介绍_基础知识

AngularJS 指令 AngularJS 通过被称为 指令 的新属性来扩展 HTML. AngularJS 通过内置的指令来为应用添加功能. AngularJS 允许你自定义指令. AngularJS 指令 AngularJS 指令是扩展的 HTML 属性,带有前缀 ng-. ng-app 指令初始化一个 AngularJS 应用程序. ng-init 指令初始化应用程序数据. ng-model 指令把元素值(比如输入域的值)绑定到应用程序. 完整的指令内容可以参阅 AngularJS 参考

javaScript中两个等于号和三个等于号之间的区别介绍_基础知识

一言以蔽之:==先转换类型再比较,===先判断类型,如果不是同一类型直接为false. ===表示恒等于,比较的两边要绝对的相同 alert(0 == ""); // true alert(0 == false); // true alert("" == false); // true alert(0 === ""); // false alert(0 === false); // false alert("" === fal

javascript运算符——位运算符全面介绍_基础知识

前面的话 位运算符是非常底层的运算,由于其很不直观,所以并不常用.但是,其速度极快,且合理使用能达到很好的效果.本文将介绍javascript中常常被忽视的运算符--位运算符 二进制表示 ECMAScript中的所有数值都以IEEE-754 64位格式存储,但位操作符并不直接操作64位的值,而是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数 这种位数转换使得在对特殊的NaN和Infinity值应用位操作时,这两个值都会被当成0来处理 如果对非数值应用位操作符,会先使用Num

javascript编码的几个方法详细介绍_基础知识

escape定义和用法 escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串. 参数 描述 string 必需.要被转义或编码的字符串.   返回值 已编码的 string 的副本.其中某些字符被替换成了十六进制的转义序列. 说明 该方法不会对 ASCII 字母和数字进行编码,也不会对下面这些 ASCII 标点符号进行编码: * @ - _ + . / .其他所有的字符都会被转义序列替换. 提示和注释 提示:可以使用 unescape() 对 escape() 编码的