`
yiminghe
  • 浏览: 1452786 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

querySelectorAll 探讨

阅读更多

随着css selector engine在越来越多的javascript库中实现,进而影响了浏览器开发商,在现代(除了ie)的浏览器中都实现了css selector api : querySelector,querySelectorAll ,利用原生的 render engine ,速度得到了极大的提高,最终反馈到新的javascript库中,在进行选择器筛选时都要首先进行能力检测(feature test),适时地选择原生实现。


这里说明一下使用原生 querySelectorAll  会遇到的问题以及解决思路:


node.querySelectorAll (selector) ,根据规范定义:


The querySelectorAll() method on the NodeSelector interface must, when invoked, 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.


简单的说就是在节点的子树集合中查找符合css选择串的节点集合。


测试html结构:

 

<div id="test">
	<b id="wrong"></b>
	<div id="testInner">
		<b id="ok">
		</b>
	</div>
</div>
<div>
</div>
 

 

 

而下面例子就有点奇怪:

 

 

document.getElementById("test").querySelectorAll("div b"); // 2 : wrong , ok

document.getElementById("test").querySelectorAll("div"); // 1 : testInner
 

若只在节点的子树集合中则与第一句代码矛盾,若在包括节点的子树中查找则与第二句代码矛盾,一般的来说我们期望第二句代码的结果,当限定context为一个节点时,一个css 选择器期望是从context的子节点开始匹配而不是从context节点自身开始。


以及更加诡异的

 

<div><p id="foo"><span></span></p></div>

var foo = document.getElementById("foo");
// should return nothing
// will return the SPAN (booo!)
alert(foo.querySelectorAll('div span').length)
 

 

综合判断似乎浏览器的实现是:

 

element-rooted queries are handled by "finding all the elements that match the given selector -- rooted in the document -- then filtering by the ones that have the specified element as an ancestor."

 

先在文档中找出所有符合选择器的元素,然后再根据是否其祖先结点是context来进行筛选。


库的解决


对于最先实现css selector engine 的javascript库,选择的是更符合人们期望的:给定的css selector从context 的子节点开始匹配,而现在又要尽可能的利用原生的实现,对于这个问题为了兼容性考虑,要和以往的版本保持一致,也就决定了不能简单的调用 node.querySelectorAll



1.jquery


jquery 对于 context 为 document 即没有 context 的情况,调用 document.querySelectAll ,而对于context 为节点的情况,其实转而调用的是纯dom实现的选择器引擎:

 

/* 1.4.2

line : 3528
判断只能是document才能使用原生
context === document ,只使用 document.querySelectorAll
 if ( !seed && context.nodeType === 9 && !isXML(context) ) {
  try {
   return makeArray( context.querySelectorAll(query), extra );
  } catch(e){}
} 
 
 
line:2746 oldsizzel
判断必须是包含在context节点中
 contains(context, checkSet[i])) ) 
*/

$("#test").find("div b"); // 1 : ok
 

 

2.yui3

 

yui3 则是采用一种比较聪明的做法,利用 id 选择器强制限制context,例如


document.getElementById("test").querySelectorAll("div b") 则被强制转换为


document.getElementById("test").querySelectorAll("#test div b")

 

也即:document. querySelectorAll("#test div b")

 

这样强制下层选择器从子节点开始匹配:使得 context中的querySelectorAll 变得无关紧要

 

YUI({filter:"DEBUG"}).use("node",function(Y){
		
		/*line 2597
		 enforce for element scoping
            if (node.tagName) {
                node.id = node.id || Y.guid();
                prefix = '[id="' + node.id + '"] ';
            }
            
     然后 document.getElementById("test").querySelectorAll("#test div b");       
	*/
		Y.one("#test").all("div b"); // 1:ok
	});

 

3.Extjs


extjs 我认为采用的是一种比较落后的做法,虽然采用了创新的编译函数 做法,但其根本没有采用浏览器的原生实现,不过也自然免除了这种特殊情况的考虑:

 

Ext.get("test").select("div b") //1:ok

 

PS: john resig 很早就注意到了这个问题 ,并在 Secrets of the JavaScript Ninja   11章正式说明了这个情况,虽然解释比较奇怪:


When performing an element-rooted query (calling querySelector or
querySelectorAll relative to an element) the selector only checks to see if the final portion of the
selector is contained within the element.


 

书中提出了同yui3类似的方法,且不具有侵入性:

 

(function () {
    var count = 1;
    this.rootedQuerySelectorAll = function (elem, query) {
        var oldID = elem.id;
        //解决奇怪的浏览器api问题
        elem.id = "rooted" + (count++);
        //CSS Selector Engine
        try {
            return elem.querySelectorAll("#" + elem.id + " " + query);
        } catch(e) {
            throw e;
        } finally {
            //不具有侵入性  
            elem.id = oldID;
        }
    };
})();
 

 

 

 

分享到:
评论

相关推荐

    checkbox全选反选与批量删除附源码

    在本例中,我们将探讨如何利用HTML的`checkbox`元素,JavaScript来实现全选/反选功能,并通过Servlet来处理数据库中的批量删除操作。 **一、Checkbox全选与反选** 1. **Checkbox基本概念**:Checkbox是HTML中的一...

    如何在 JavaScript 中迭代表行.docx

    在这篇文章中,我们将深入探讨如何使用JavaScript来迭代表格中的行,并提供实际的代码示例。 首先,HTML表格是由`&lt;table&gt;`标签定义的,它由一系列`&lt;tr&gt;`行标签和`&lt;td&gt;`单元格标签组成。要在JavaScript中操作这些...

    Looping through a HTML list with JavaScript.zip

    本文将深入探讨如何使用JavaScript有效地循环遍历HTML列表,并提供实际的代码示例。 首先,HTML列表通常由`&lt;ul&gt;`(无序列表)或`&lt;ol&gt;`(有序列表)元素构成,其中包含一系列`&lt;li&gt;`(列表项)元素。JavaScript提供了...

    table里面获取所有元素

    这篇博客“table里面获取所有元素”可能探讨了如何在JavaScript或相关的前端技术中实现这一功能。 首先,我们需要理解HTML中的表格结构。一个基本的表格由`&lt;table&gt;`元素作为容器,`&lt;tr&gt;`(行)元素来定义每一行,`...

    Javascript获取相同CSS样式的元素

    总结来说,这篇博文可能探讨了如何使用JavaScript高效地查找和操作具有相同CSS样式的HTML元素,涉及到了`querySelectorAll`、属性选择器和`getComputedStyle`等技术。这些技能对于前端开发者来说是非常重要的,能够...

    省份城市xml解析js代码

    本篇将深入探讨如何使用JavaScript解析XML,特别是针对省份城市的数据。 首先,我们需要加载XML文件。在浏览器环境中,我们可以使用`XMLHttpRequest`对象或`fetch` API来获取XML文件内容。例如: ```javascript ...

    获得所有相同控件的id

    在本篇文章中,我们将深入探讨如何使用JavaScript来获取页面中所有具有相同ID的控件,并进一步检查这些ID是否包含特定的字符串。这个问题虽然看似简单,但实际上涉及到DOM操作、字符串处理等多个方面,对于初学者来...

    JavaScript复选框相关函数

    下面我们将深入探讨与复选框相关的JavaScript函数以及如何实现全选和全不选的功能。 一、HTML中的复选框 在HTML中,复选框是通过`&lt;input&gt;`标签创建的,类型设置为"checkbox"。例如: ```html ``` 二、JavaScript...

    JS控制checkboxJS控制checkboxJS控制checkbox

    本文将深入探讨如何使用JavaScript来控制checkbox的行为,包括选择、取消选择、检查状态以及处理与checkbox相关的事件。 一、获取checkbox 在JavaScript中,可以通过`document.getElementById`、`document....

    JS DOM操作备忘

    这篇备忘将深入探讨如何利用JavaScript进行DOM操作,包括选择元素、遍历节点、添加删除元素以及更新属性。 1. **选择元素** - `getElementById()`:根据ID获取元素,如`document.getElementById('myID')`。 - `...

    gridview全选(js实现)

    本文将详细探讨如何通过JavaScript实现GridView的全选功能,并提供相关代码示例。 首先,我们需要了解JavaScript的基本语法和DOM(文档对象模型)操作。DOM是HTML和XML文档的编程接口,允许我们通过JavaScript来...

    js全选/反选

    在本话题中,我们将深入探讨如何使用JavaScript实现全选和反选的功能。 一、全选功能 全选功能通常通过一个复选框(checkbox)触发,当用户点击这个复选框时,所有的子项(其他复选框)都会被自动选中。以下是一个...

    用js驱动产生条纹式表格

    这篇名为“用js驱动产生条纹式表格”的博文主要探讨了如何使用JavaScript来创建具有条纹样式的HTML表格,以增强数据展示的视觉效果。条纹式表格在网页设计中常见于数据密集型的应用,如报表或数据库查询结果,它通过...

    去掉超连接的下划线

    本文将深入探讨如何通过JavaScript代码模块来实现“去掉超连接的下划线”的目标。 首先,我们需要理解HTML中的`&lt;a&gt;`标签,它是用于创建超链接的元素。默认情况下,`&lt;a&gt;`标签内的文本会被浏览器加上下划线。我们可以...

    06-作业解答 获取元素方式_web_

    在“06-作业解答 获取元素方式_web_”这个主题中,我们主要探讨的是WEB前端编程的基础知识,特别是关于如何在网页上获取和操作元素的技术。这是一个适合小白入门的教程,旨在帮助初学者从基础到精通逐步掌握前端...

    Web APIs-Dom获取&属性操作(理论+实战篇)-获取随机图片案例资料

    本资料主要探讨的是如何利用JavaScript来获取DOM元素以及进行属性操作,并通过一个获取随机图片的实战案例进行深入讲解。 首先,了解DOM的基本操作。在JavaScript中,我们可以使用`document.getElementById`、`...

    Javascript--DOM.rar_javascript

    本篇文章将深入探讨JavaScript操作DOM的各种技术和实践。 一、DOM的基本概念 DOM是一个树形结构,每个节点代表HTML或XML文档的一部分,如元素、属性、文本等。通过DOM,我们可以查找、修改、添加或删除文档的任何...

    JS控制复选框全选、反选,可进行同一页面多个复选框全选控制V2 .0

    在本项目"JS控制复选框全选、反选,可进行同一页面多个复选框全选控制V2.0"中,我们将探讨如何利用JavaScript实现对复选框(checkbox)的全选、反选功能,并获取选中的复选框的值。这些功能在用户界面中常见于批量...

    遍历网页中的元

    本主题主要针对具有较强编程基础的开发者,我们将深入探讨如何遍历网页中的元数据,包括元标签(meta tags)、链接、图片、表单等。 一、HTML元数据 元数据是网页中非可视化的信息,通常用于提供关于网页内容的额外...

Global site tag (gtag.js) - Google Analytics