【亚洲必赢官网】CSS接纳引擎,及些许感性通晓

简讯:W3C 发布 CSS 选择器 API 规范

2012/07/04 · CSS ·
CSS

英文原稿:W3C,编译:iteye

W3C 的 Web 应用工作组近来颁布了 CSS 接纳器 API 规范的 Level 1 版本和
Level 2 版本。

该标准定义了经过匹配采取器从 DOM
获取成分节点的主意,日常适用于履行文档中一组特定成分的 DOM(Document
Object
Model,文档对象模型)操作。这一个措施简化了获取一定成分的历程,尤其是指向更麻烦的技术定义以及过去使用的成分。

亚洲必赢官网 1

W3C 同时还发表了该标准的 Level 2 本子,在 Level 1 的底蕴上,添加了
matches 方法、引用节点操作、:scope 伪类等有关标准。

你可以在 7 月 19
日以前针对该规范提交意见,该日期未来它将改为一个“提议”版本,并最终成为正式版本。

专业查看:

●CSS 选择器 API Level
1

●CSS 选择器 API Level
2

【亚洲必赢官网】CSS接纳引擎,及些许感性通晓。 

赞 收藏
评论

亚洲必赢官网 2

querySelectorAll 相比较下边那一个艺术有如何分别?

第15章 CSS选用引擎 {#15-css}

趁着web开发越发规范,所有流行的浏览器都富含了W3C选拔器API。那么些API提供了querySelectorAll()和querySelector()五个措施,在大家运用中结成其他一些好的工具得以写出满意跨浏览器须要的可以便捷遍历DOM的代码。

注意 想要获得越多关于API音信么?请查看W3C
Level1(www.w3.org/TR/selectors-api/)和W3C
Level2(www.w3.org/TR/selectors-api2/)。

你或许会问,大概在拥有的浏览器中都兑现了W3C接纳器API,为啥大家还要花时间来谈谈哪些贯彻纯JavaScript的CSS选取器引擎呢?

尽管存在这几个专业的API是件好事,可是多数浏览器只是生硬地促成了。那样的做法就与一个好的API不沾边了。例如,那样方法无法采取已经创建好的DOM缓存,它们不可以提供错误报告,它们也不可能处理任何款式的恢弘。

风行的JavaScript类库中的CSS选取器考虑到了这么些要素。他们接纳DOM缓存提供更高的性质,它们提供了错误报告,它们具有很高的扩充性。

提示CSS拔取器引擎是一个效能性的术语,它通过CSS表明式来匹配DOM元素,例如,.ninja的表明式可以匹配所有class为ninja的因素。

说了这么多,依然没有回答难题:为何需求了解纯JavaScript的CSS接纳器引擎是哪些行事的吗?了解这一个自然是为了惊人的习性收益了。那样做不只是可以已毕更快、更好的遍历方法,也足以让自身打听到什么创制适应CSS选用器引擎的更高品质的CSS选择器。

CSS采取器引擎近来是惯常开销中的一有些,明白它们怎么样行事、怎么样使它们工作更快可以在支付为大家提供基本的鼎力相助。即便你在自忖大家要什么样做,首要服从以下格局:

  1. 查找DOM元素。
  2. 对它们做一些业务。

而外新的抉择器API,查找DOM成分一直都不是任重先生而道远。那几个API对于使用ID只怕标签名查找API有限定。不管怎么说,第一步做起来是相比较简单的,让咱们把重点放在第二步上。

CSS3选拔器引擎标准被W3C定义在www.w3.org/TR/css3-selectors/。

有三种重大的已毕CSS拔取器引擎的措施:

  • 选用之前提到的W3C选用器API。
  • 行使过多浏览器中放到的XPath语言
  • 使用纯粹的DOM,要是前多个功用不设有,它就是主要的CSS拔取器引擎

本章将会深深地探究那一个方针,可以允许大家决定去完毕仍旧领悟一个JavaScript
CSS选用器引擎。

我们将从W3C的办法初步。

学完 JavaScript,还在纳闷其效果的时候,DOM
蹦了出来。有些莫明其妙,几番查阅唯有,意识到温馨拥有广大误会,将新的领悟总括出来,以供之后再来审视。

(1)getElementsByTagName

15.1 W3C选择器API {#15-1-w3c-api}

W3C选拔器API是一个相比新的API,在JavaScript中动用它完成一体化的CSS选取器引擎可以减掉过多工作量。

浏览器供应商抓住了这些新的API,并且在大多数浏览器中落到实处了它(safari
3,IE8,Chrome,和Opera10)。API一般情况下帮助具有CSS引擎完成的选拔器,因而一个浏览器是不是完全接济CSS3,从它的选择器的兑现上就可以突显出来。

API提供了一部分立见功效的艺术,它们之中的多个在风靡的浏览器中已经落成了:

  • querySelector()
    接收一个CSS选拔器字符串并且再次回到第二个元素,若是没有找到再次回到null。
  • querySelectorAll()
    接收一个CSS选用器字符串并且重临一个静态的NodeList,其中涵盖查找到的保有因素。

在四个法子在所有的DOM成分,DOM文档,DOM框架中设有。

上面的代码突显什么利用那么些API。

Listing 15.1 Examples of the Selectors API in action

<div id="test">
<b>Hello</b>, I'm a ninja!
</div>
<div id="test2"></div>
<script type="text/javascript">
window.onload = function () {
//Finds <div> elements that are children of the body
var divs = document.querySelectorAll("body > div");
assert(divs.length === 2, "Two divs found using a CSS selector.");
//Finds only children who are bold!
var b = document.getElementById("test")
.querySelector("b:only-child");
assert(b,
"The bold element was found relative to another element.");
};
</script>

比较之下其余JavaScript类库的完毕,浏览器完成的API只在少数的水准上支撑了CSS拔取器。那么些标题能够在根成分的查询规则中反映出来(调用querySelector()和querySelectorAll()都得以)。

Listing 15.2 Element-rooted queries

<div id="test">
<b>Hello</b>, I'm a ninja!
</div>

<script type="text/javascript">
window.onload = function () {
var b = document.getElementById("test").querySelector("div b");
assert(b, "Only the last part of the selector matters.");
};
</script>

留神:执行那一个查询时,拔取器只会在要素内部查找与表达式中最后一有些匹配的成分。这一个看起来与直觉想违背的。在listing
15.2中,大家得以见见在id为test的要素中并从未div,不过这几个选拔器却是成功的。

那种景观与一大半人想像的都差距,所以大家必要提供一个搞定方案。最广大的措施是为根节点元素提供一个新的id,更改它的上下文。

Listing 15.3 Enforcing the element root

<div id="test">
<b>Hello</b>, I'm a ninja!
</div>
<script type="text/javascript">
(function() {
//使用立即执行方法将计数器变量绑定到rootedQuerySelectorAll()方法上
var count = 1;

// 将方法定义到全局定义域上
this.rootedQuerySelectorAll = function (elem, query) {

// 保存原始的id,之后我们再将它设置回来
var oldID = elem.id;

// 分配唯一的临时
elem.id = "rooted" + (count++);

try {
return elem.querySelectorAll("#" + elem.id + " " + query);
}

catch (e) {
throw e;
}

finally {
//在finally模块中重置原始的id,这样可以保证代码永远会执行
elem.id = oldID;
}
};
})();

window.onload = function () {
var b = rootedQuerySelectorAll(
document.getElementById("test"), "div b");
assert(b.length === 0, "The selector is now rooted properly.");
};
</script>

在listing15.3中有两点对比紧要。

一开首,大家不能不为因素分配一个唯一的id,并且存储此前的id。那样是为着确保在大家创制选用器的时候取得的结果不会时有爆发顶牛。然后大家将那些id预置到拔取器此前(格局是“#id”,id是唯一值)。

先后会简单地移除id并且重临查询结果。然则注意一点:采取器API可以抛出格外(常常是选项器语法错误大概不接济选用器)。基于这几个原因,我们选择try/catch语法。由于我们想要重设id,我们可以添加一个万分的finally模块。那是言语自己的特色:即使大家在try中回到只怕在catch中抛出格外,代码最后都会执行finally模块(执行会早于当前形式的回来)。通过那种办法id总是被设置科学的。

拔取器API是W3C提议最有前途的API之一。在协理那种API的浏览器主导市场后,它就可以通过很简短的章程替代大部分JavaScript类库中的半数以上工作了。

改换注意力,让大家以XML的方法化解那几个题目。

DOM vs HTML

DOM 是怎么,在哪能收看 DOM 吗?使用浏览器阅读网页的时候,按
<kbd>f12</kbd> 打开开发者工具,你会看出那样的画面

亚洲必赢官网 3

标明的局地,就是时常听别人说的 DOM 了。

看起来,那一个大家写的 HTML 就好像一样啊。

亚洲必赢官网 4

如果再研商商讨,就能窥见,两者依旧有点区其余。下边是对 DOM
进行了操作的结果。

亚洲必赢官网 5

(2)getElementsByClassName

15.2 使用XPath查找元素 {#15-2-xpath}

对此那一个不扶助接纳器API的浏览器,统一地利用XPath查询。

XPath是在文档中查找成分的语言。它明显地要强于古板的CSS采用器,超过半数风行的浏览器(Firefox,
Safari 3+,Opera
9+,Chrome)都援救了XPath,它可以应付基于HTML的DOM文档。IE6及以上提供支持XML文档的XPath(并不是HTML文档——它是咱们联合的目标)。

选拔XPath表明式替代纯粹的DOM操作可以取得的收入并从未一个确定的正规。由于编程的法子那些正式被确定后,依旧亟待精通有些业务:通过纯粹的DOM方法运用id或许标签来搜寻成分依然是相比快的(使用getElementById()和getElementByTagName())。

万一大家面对的观众可以清爽地使用XPath表明式(并且很春风得意地将协调限制在主流的浏览器上),我们就足以上边那段代码(Prototype类库提供)并且完全忽视任何关于CSS选取器引擎的东西。

Listing 15.4 A method for executing an XPath expression on an HTML
document

if (typeof document.evaluate === “function”) {

function getElementsByXPath(expression, parentElement) {

var results = [];

var query = document.evaluate(expression, parentElement || document,
null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

for (var i = 0, length = query.snapshotLength; i < length; i++)

results.push(query.snapshotItem(i));

return results;

}

}

利用XPath可以很好的处理所有事情,不过其实根本不太实用。XPath封装的那几个意义是为开发人士使用的,并且相对于CSS选拔器而言它过度复杂了。大家在此处无法收看完好的XPath,可是table
15.1提供了最常用的XPath表明式,并且提供了与它们对应的CSS选拔器。

Table 15.1 CSS selectors and their equivalent XPath expressions

Goal XPath CSS3
All elements //* *
All elements named p //p P
All immediate child elements of p //p/* P > *
Element by ID //*[@id=’foo’] #foo
Element by Class //*[contains(concat(“”,@class,””),”foo”)] .foo
Element with attribute //*[@title] *[title]
First child of all p //p/*[0] P > *:first-child
All p with an a descendant //p[a] Not possible
Next element //p/following-slibling::*[0] P + *

相对于采取纯粹的DOM拔取器引擎,我得以拔取XPath表明式创设选用器引擎,并且动用正则转换选取器。分歧之处是将CSS接纳器映射为与之对应的XPath表达式,然后实施。

因为大气的DOM
CSS选择器引擎的落实,这几个方法并没有带来太多方便大家的东西。许多开发者不利用XPath是为着减小他们引擎的复杂程度。你须求权衡使用XPath引擎带来的低收入(尤其是相比选取器API)。

当今上马卷起大家的袖管。

DOM vs JS

  • 1993 年,HTML 发布
  • 1996 年,JavaScript 发布
  • 1996 年,CSS 发布
  • 1998 年,XML 发布

岁月先暂停在 1998 年以前,未来人们有了 HTML 表达文档的情节,CSS
描述文档的体制,也有了 JavaScript,但随即并没有 DOM 标准。那表示,例如
.addEventListener
之类的措施不恐怕选取。也就是说,怎么「操作」文档,那不是
JavaScript[\[1\]](https://www.jianshu.com/p/c4f2af059bf7#fn1)
的范畴!

换言之,此前以为 .addEventListener 是 JavaScript 的东西,实则 DOM
定义的 API。

回去 1998 年前,当时怎么利用 JS
操作文档,是从未有过统一的专业的——一切取决于浏览器,各家厂商都有本身的定义方式——非标准性质的
DOM 出现。然后 IE4 和 Netscape Navigator 4 又分别退出了祥和的 DOM
扩张,增强 JavaScript 的效果,也称为 Dynamic HTML(简称
DHTML)。那段时代的 “DOM”,习惯上也改为 DOM Level 0,
是历史中的一个参考点,而非正式的标准规范。

(3)getElementsByName

15.3 纯DOM实现 {#15-3-dom}

在每一种CSS选用器引擎的为主都是一个纯粹的DOM完成。它的渴求是更换CSS选取器并且应用已存在的DOM方法(getElementById()getElementByTagName())查找符合的要素。

注意 HTML5在正式方法中添加了getElementsByClassName()方法。

利用DOM完成CSS选用器有一部分最首要的因由:

  • IE6、7——IE8和9已经援救了querySelectorAll(),IE6和IE7却漏掉了XPath或然选用器API,所以利用DOM完成就变得必须了。
  • 向后特出——倘若你想要你的代码优雅降级并且支持这一个不扶助选用器API可能XPath的浏览器(比如Safari
    2),你就要求采用DOM情势来兑现。
  • 速度——有好多彻头彻尾的DOM选拔器质量尤其好(例如使用ID查找成分)。
  • 全盘覆盖——并不是享有的浏览器都接济相同集合的CSS选取器。若是大家想要在装有浏览器中援救具备那么些CSS采用器集合——恐怕至少是这个最常用的,大家就需求倚重温馨的力量了。

纪事这一个,我们得以想到三个或许的CSS拔取器引擎的完毕:从上到下和从下到上。

从上到下的选用器引擎将CSS选拔器从左至右举办辨析,然后依据每一种选拔器片段匹配成分。在一大半JavaScript类库中都可以找到那种发动机,查找元素时优先采纳那种工具。

看上边那几个大约的例证:

<body>
  <div></div>
  <div class='ninja'>
    Please <a href='/ninja'>Click me!</a>
  </div>
<body>

要是大家想要找到包罗“Click
me!”的<span>,大家可以运用上面那么些选用器:

div.ninja a span

从上到下的办法在Figure 15.1中一度勾勒了。

第一步,div.ninja标识了document中的子树。下一步,在子树中运用a标识了锚点成分。最终span标识了最后的目的成分。注意,那是一个概括的例证。在其他等级都能够标识复杂的子树。

当开发拔取器引擎时索要考虑多少个重要的注意事项:

  • 那个结果须求按照文档的各类(它们被定义时的逐条)。
  • 那几个结果应当是唯一的(不该回到重新的成分)。

由于这么些方面的设想,开发从上到下的引擎是相比较复杂的。

来看一个简化的完毕,使用标签名查找成分。

Listing 15.5 A limited, top-down selector engine

<div>
  <div>
    Span
  </div>
</div>

<script type="text/javascript">
window.onload = function(){
  function find(selector, root){
    //If no root provided, starts at the top of the document
    root = root || document;

    //Splits the selector on spaces, grabs the first term, collects the remainder, finds the element matching the first term, and initializes an array to gather the results within
    var parts = selector.split(" "), query = parts[0], rest = parts.slice(1).join(" "), elems =  root.getElementsByTagName(query), results = [];

    for (var i = 0; i < elems.length; i++) {
      if (rest) {
        //Calls find() recursively until all the selectors are consumed
        results = results.concat(find(rest, elems[i]));
      }
      else {
        //Pushes found elements onto results array
        restesults.push(elems[i]);
      }
    }

    //Returns list of matched elements
    return results;
  };

  var divs = find("div");
  assert(divs.length === 2, "Correct number of divs found.");

  var divs = find("div");
  assert(divs.length === 2, "Correct number of divs found.");

  var divs = find("div", document.body);
  assert(divs.length === 2, "Correct number of divs found in body.");

  var divs = find("body div");
  assert(divs.length === 2, "Correct number of divs found in body.");

  var spans = find("div span");
  assert(spans.length === 2, "A duplicate span was found.");
};
</script>

在那么些完结中大家做了一个限量,这么些引擎只好寻找标签名。那些引擎可以解释为多少个步骤:解析过滤器,查找成分,过滤,检索和联合元素。

自家接中远距离观看每一个步骤。

发展

1. W3C 标准
querySelectorAll 属于 W3C 中的 Selectors API 规范 [1]。而
getElementsBy 体系则属于 W3C 的 DOM 规范 [2]。

15.3.1 解析接纳器 {#15-3-1}

在大家简要的例子中,大家只将标签名格局的CSS采用器转换为字符串数组,例如“div
span”转换为[“div”, “span”]。

其一差不离的例证使用空白分隔符将字符串隔断,可是CSS2和CSS3有力量运用质量可能属性值来寻找成分,因而大概在选用器中会多出其余一些空格。那就使得大家事先使用的法子看起来过于简化了。

为了完整的完结,大家想博得一体系可靠的辨析规则,用来处理那此抛过来的其它表明式;那些规则最或许的就是选择正则表达式。上面的事例利用正则表明式体现格外健全的分析能力,它可以捕获选拔器的逐个部分并将它们截断(即使有须要的话用逗号分隔)。

Listing 15.6 A regular expression for breaking apart a CSS selector

<script type="text/javascript">
  var selector = "div.class > span:not(:first-child) a[href]"
  var chunker = /((?:\([^\)]+\)|\[[^\]]+\]|[^ ,\(\[]+)+)(\s*,\s*)?/g;
  var parts = [];
  //Resets the position of the chunker regexp (start from beginning)
  chunker.lastIndex = 0;

  //Collects the pieces
  while ((m = chunker.exec(selector)) !== null) {
    parts.push(m[1]);
    //Stops on encountering a comma
    if (m[2]) {
      extra = RegExp.rightContext;
      break;
    }
  }

  assert(parts.length == 4, "Our selector is broken into 4 unique parts.");

  assert(parts[0] === "div.class", "div selector");

  assert(parts[1] === ">", "child selector");

  assert(parts[2] === "span:not(:first-child)", "span selector");

  assert(parts[3] === "a[href]", "a selector");

</script>

很显著,那一个选取器只是拼图中的一片段。大家须求为每一种表明式添加额外的辨析规则。半数以上选拔器引擎都包涵一个正则表明式与办法的炫耀,当采纳器中某部分匹配上时,关联的主意就会举行。

商讨这一个表明式的细节会成本很多时日。若是您确实想商讨它是何等做的,我们鼓励你去看jQuery的源代码大概其余你感兴趣的类库的源代码,研商采纳器解析那有些。

下边,大家须求找到正则表达式匹配的要素。

DOM Level 1

  • 1998 年,DOM Level 1 发布

W3C 正式揭橥了 DOM,名为 DOM Level 1,主要为了炫耀文档结构,由两块组成:

  • Core:映射以 XML 为根基的文档结构
  • HTML:基于 Core 举办了伸张,添加针对 HTML 的靶子和格局

2. 浏览器包容
querySelectorAll 已被 IE 8+、FF 3.5+、Safari 3.1+、Chrome 和 Opera 10+
杰出协理 。
getElementsBy 体系,以最迟添加到规范中的 getElementsByClassName 为例,IE
9+、FF 3 +、Safari 3.1+、Chrome 和 Opera 9+ 都已经支撑该措施了。

15.3.2 查找成分 {#15-3-2}

有很多措施可以找到科学的要素。这个技能倚重于浏览器协理什么技能以及哪些是实惠的。可是,依然有不少眼看的办法的。

getElementById()只在HTML文档的根节点上是实惠的,那方法会在文档中查找指定id的第二个成分(正是那几个缘故那个id的因素应该唯有一个),由此CSS
ID选拔器是一蹴而就的。令人恼火的是IE和Opera还会将name一样的第四个因素查找出来。要是大家只愿意物色ie,大家就须求一个外加的注脚步骤来去除这么些不必要的因素。

只要大家想要找到与指定id匹配的有着因素(那是CSS选用器的习惯,尽管逐个页面被确定唯有一个指定id的成分),我必要遍历所有因素只怕使用document.all[“id”]。document.all[“id”]将享有匹配的要素以数组的样式再次来到,支持此办法的浏览器蕴涵IE,Opera,和Safari。

getElementByTagName()方法依照标签名匹配成分,别的一种用法就是透过*做为标签名方可搜寻文档只怕成分中的所有因素。在拍卖根据属性的拔取器(例如:.class或然[attr])的时候那种措施是那么些实惠的。

使用*的时候有一个警戒,IE重返的结果中概括注释节点(因为标签的节点名是!,由此会被再次来到)。所以须求过滤注释节点。

getElementsByName()是一个非常不难完毕的法门,它的目的是摸索指定名称的富有因素(例如<input>标签和那一个拥有name属性的价签)。完结这一个[name=name]采用器是卓殊实用的。

getElementByClassName()是一个新的HTML5方法。它是基于class属性来搜寻成分的。这些措施巨大地升高了类选取器的进程。

虽说有无数技巧可以被用来贯彻接纳器,可是上述大家所说的不二法门是寻觅成分时最重点的格局。

动用这几个措施的结果,大家移动到过滤部分。

DOM Level 2

  • 2000~2003 年,DOM Level 2 发布

2 级 DOM 对从前的 Core 进行了开展,接济了 XML
的命名空间,而且引入了越来越多的模块:

  • Views:描述跟踪一个文档的种种视图(使用 CSS 样式设计文档前后)的接口
  • 伊芙nt:描述事件接口
  • Style:描述处理按照 CSS 样式的接口
  • Traversal and Range:描述遍历和操作文档树的接口

3. 接到参数
querySelectorAll 方法接收的参数是一个 CSS 选拔符。而 getElementsBy
连串接收的参数只好是纯粹的className、tagName 和 name。代码如下 [3]:

15.3.3 过滤集合 {#亚洲必赢官网 ,15-3-3}

一个CSS表明式平时包蕴众多独立的部分。例如div.class[id]含蓄多个部分:它会招来那多少个类名为class并且具有一个属性名为id的div成分。

首先步是标识根选用器。例如,大家看到选拔了div,所以大家采取getElementsByTagName()方法遍历页面上装有的div成分。然后,大家过滤出那么些结果中只含有指定类名和持有id属性的因素。

这么些过滤的听从普遍于具有的选用器中。过滤器中的内容最要紧的是拍卖成分的性质和依据成分的弟兄节点和其余关系确定地方。

  • 质量过滤——那些方法的完结是访问DOM的特性(一般选用getAttribute方法)和验证它们的值。Class过滤是以此办法的一种格局(访问className属性并检查它的值)。
  • 地方过滤——例如拔取器:nth-child(event)大概:last-child,它们是应用在父成分上的各个格局的结合体。在那一个辅助它的浏览器中运用children(IE,Safari,Chrome,Opera,和Firefox3.1),children中隐含所有的child成分。所有的浏览器都饱含childNodes,它包蕴子成分列表,其中也包罗text节点和注释。使用这二种方法可以达成种种样式的元素地点过滤。

构建一个过滤器方法有两个目的:我们可以为用户提供一个不难易行的艺术用来测试它们的因素,并且大家可以高速的检查一个要素是还是不是与指定选用器匹配。

近来让大家关注细化结果的工具。

15.3.4 遍历与统一

选取器引擎必要有力量去遍历(查找后裔成分)和集合结果。不过像我们listing那样,大家的初步已毕还差得很远。大家最后的结果是获取五个<span>成分,而不是一个。大家要求引入一个附加的反省来确保重回的数组中有唯一的结果。半数以上从上到下的拔取器引擎都具备保持一致性的工具。

不幸运的是,没有一个概括的办法可以保证DOM成分的一致性,所以大家需求协调来落到实处它。大家会遍历这么些要素并为它们分配临时的标识,因而我们得以表明大家是还是不是碰到过它们。

Listing 15.7 Finding the unique elements in an array

//Sets up our willing test subjects.
<div id="test">
  <b>Hello</b>, I'm a ninja!
</div>

<div id="test2"></div>
  <script type="text/javascript">
    (function(){
       //Defines the unique() function inside an immediate function to create a closure that will include the run variable but hide it from the outside world.
      var run = 0;

      //Accepts an array of elements and returns a new array containing only unique elements from the original array.
      this.unique = function(array) {

      var ret = [];
      //Keeps track of which run we’re on. By incrementing this value each time the function is called, a unique identifier value will be used for testing for uniqueness.
      run++;

      for (var i = 0, length = array.length; i < length; i++) {
        var elem = array[i];

        //Runs through the original array, copying elements that we haven’t “seen” yet, and marking them so that we’ll know whether we’ve “seen” them or not.
        if (elem.uniqueID !== run) {
          elem.uniqueID = run;
          ret.push(array[i]);
        }
      }

      //Returns the resulting array, containing only references to unique elements.
      return ret;
    };
  })();

  window.onload = function(){
    //Tests it! The first test shouldn’t result in any removals (as there are no duplicates passed), but the second should collapse down to a single element.
    var divs = unique(document.getElementsByTagName("div"));
    assert(divs.length === 2, "No duplicates removed.");

    var body = unique([document.body, document.body]);
    assert(body.length === 1, "body duplicate removed.");
};

</script>

unique()方法在检查数组中的成分时为它们添加了额外的习性,标记它们是被看过的。遍历已毕后,唯有唯一的成分被复制到结果的数组当中。在具有的类库中都会发觉这种验证办法。

想要精晓属性绑定那部分可以回看13章中提到到事件的那部分。

上面大家着想的都是从上到下的法子。让大家快速粗略地精通一下其它一种方法。

DOM Level 3

  • 2003~2004 年,DOM Level 3 发布

此时,新引入了二者模块:

  • Load and Save:统一格局加载和保存文档的措施
  • Validation:描述了注明文档的不二法门

对 Core 再次举行了开展,援救 XML 1.0 规范,涉及 XML Infoset、XPath 和
XML Base。

var c1 = document.querySelectorAll('.b1 .c');
var c2 = document.getElementsByClassName('c');
var c3 = document.getElementsByClassName('b2')[0].getElementsByClassName('c');

15.3.5 从下到上的拔取器引擎 {#15-3-5}

只要您不关注成分唯一性的话,从下到上的选用器引擎也是一个挑选。从下到上的采纳器引擎与从上到下是倒转的。

假使选取器是div
span,选用器引擎会先找出具有的<span>成分,然后搜索各个成分的<div>祖先成分。那种拔取器引擎在大部浏览器引擎中都会找到。

这种发动机并不像从上到下的艺术那样流行。即使对于简易的拔取器(子选拔器)它运行起来相当卓绝,遍历祖先费用非凡大。然则它的容易性值得我的丑爹产权衡。

这几个引擎的结构万分简单。在CSS选拔器中我们摸索最终的表明式,然后遍历合适的成分(就如从上到下引擎,可是选取的是最终的表明式)。从此开端,所有的操作都是一多种的过滤操作和一些在经过中删去成分的操作(看下边的代码)。

Listing 15.8 A simple bottom-up selector engine
<div>
  <div>
    Span
  </div>
</div>

<script type="text/javascript">
  window.onload = function(){
    function find(selector, root){
      root = root || document;
      var parts = selector.split(" "),
          query = parts[parts.length - 1],
          rest = parts.slice(0,-1).join(""),
          elems = root.getElementsByTagName(query),
          results = [];

      for (var i = 0; i < elems.length; i++) {
        if (rest) {
          var parent = elems[i].parentNode;
            while (parent && parent.nodeName != rest) {
              parent = parent.parentNode;
            }

          if (parent) {
            results.push(elems[i]);
          }
        } else {
          results.push(elems[i]);
        }
      }
      return results;
    };

    var divs = find("div");
    assert(divs.length === 2, "Correct number of divs found.");

    var divs = find("div", document.body);
    assert(divs.length === 2, "Correct number of divs found in body.");

    var divs = find("body div");
    assert(divs.length === 2, "Correct number of divs found in body.");

    var spans = find("div span");
    assert(spans.length === 1, "No duplicate span was found.");
  };
</script>

Listing 15.8
突显了从下到上引擎的结构。注意它只向上查找了一流。假使想要做到更深的级别就要求跟踪当前的级别。那里会回到二种方式的数组:一些未曾被装置为undefinded的要素的数组,因为它们不匹配结果。此外就是与足以正确匹配祖先成分的要素数组。

前面提到过,额外的验证祖先成分的工作会导致损失伸张性,可是它不使用保障一致性的艺术就足以生出不另行的结果,那就是它的优点。

回顾

竣事 2017-04-17,DOM Level 4 还在草稿阶段。以往再来看看 MDN 上关于 DOM
的描述:

文档对象模型 (DOM) 是 HTML 和 XML
文档的编程接口。它提供了对文档的结构化的揭橥,并定义了一种格局得以使从程序中对该社团举办走访,从而改变文档的构造,样式和内容。DOM
将文档解析为一个由节点和目的(包蕴属性和办法的目的)组成的结构集合。简言之,它会将
web 页面和本子或程序语言连接起来。

所以

  • 唯有 JavaScript 才能操作 DOM 吗?W3C
    的业内里从未规定,任何语言都足以。
  • 有 JavaScript 就决然有 DOM 吗?并不是,可以在浏览器和 Node.js
    中分头执行 console.log(document) 试试。

亟需留意的是,querySelectorAll 所接收的参数是必须严俊符合 CSS
选取符规范的。所以下边那种写法,将会抛出格外。代码如下 [4]:

15.4 总结 {#15-4}

基于JavaScript的CSS接纳器引擎难以置信的无敌。它们得以让自家动用平凡的取舍器语法轻松地稳定页面上的DOM成分。完毕一个完全的接纳器引擎必要考虑许多细节,然则随着浏览器的升级换代这几个规范会被修复的,大家并不紧缺工具。

本章大家学习到的事物:

  • 明日主流的浏览器完毕了W3C规定成分接纳的
    API,不过它们仍有不长的路要走。
  • 一经没有品质的难题,自身制造接纳器引擎对我们是有便宜的。
  • 为了创建一个采用器引擎,我们可以
  • 利用W3C APIs
  • 使用XPath
  • 为了更好的性质自个儿转换DOM
  • 从上到下的法门是最风靡的,可是它须要有些清理工作,例如确保成分的一致性。
  • 从下到上幸免了这一个操作,不过它存在质量和增添性方面的标题。

行使浏览器完毕的W3C
API,对接纳器落成的担心很快就会成为过去。对于许多开发人士来说,那些或许不会太快到来。

参考

同时援引点击链接,可以更深刻精通 DOM

  • W3C: What is the Document Object
    Model?
    & Document Object Model (DOM) Technical
    Reports
  • MDN: DOM
    概述
  • 通俗 DOM 基础——《DOM
    探索之基础详解篇》学习笔记
  • What is the
    DOM?

  1. 全文提及的 JavaScript 都指的是言语自身,而非局限于网页或其他宿主环境
try {
  var e1 = document.getElementsByClassName('1a2b3c');
  var e2 = document.querySelectorAll('.1a2b3c');
} catch (e) {
  console.error(e.message);
}
console.log(e1 && e1[0].className);
console.log(e2 && e2[0].className);

(CSS 选用器中的成分名,类和 ID 均无法以数字为开首。)

4. 返回值
多数人都领会,querySelectorAll 重回的是一个 Static Node List,而
getElementsBy 体系的归来的是一个 Live Node List。
看看上面那一个经典的事例 [5]:

// Demo 1
var ul = document.querySelectorAll('ul')[0],
    lis = ul.querySelectorAll("li");
for(var i = 0; i < lis.length ; i++){
    ul.appendChild(document.createElement("li"));
}

// Demo 2
var ul = document.getElementsByTagName('ul')[0], 
    lis = ul.getElementsByTagName("li"); 
for(var i = 0; i < lis.length ; i++){
    ul.appendChild(document.createElement("li")); 
}

因为 Demo 2 中的 lis 是一个动态的 Node List, 每五遍调用 lis
都会再也对文档举行询问,导致极端循环的难题。
而 Demo 1 中的 lis 是一个静态的 Node List,是一个 li
集合的快照,对文档的此外操作都不会对其暴发震慑。

但为啥要这么设计吧?
实际,在 W3C 规范中对 querySelectorAll 方法有明确规定 [6]:

The NodeList object returned by the querySelectorAll() method must
be static
([DOM], section 8).

那如何是 NodeList 呢?
W3C 中是那样表达的 [7]:

The NodeList interface provides the abstraction of an ordered
collection of nodes, without defining or constraining how this
collection is implemented. NodeList objects in the DOM are live.

从而,NodeList 本质上是一个动态的 Node 集合,只是规范中对
querySelectorAll 有明确须要,规定其必须回到一个静态的 NodeList 对象。

大家再看看在 Chrome 上边是个什么的情事:

document.querySelectorAll('a').toString();    // return "[object NodeList]"
document.getElementsByTagName('a').toString();    // return "[object HTMLCollection]"

那里又多了一个 HTMLCollection 对象出来,那 HTMLCollection 又是怎么着?

HTMLCollection 在 W3C 的定义如下 [8]:

An HTMLCollection is a list of nodes. An individual node may be
accessed by either ordinal index or the node’s name or id
attributes.
Note: Collections in the HTML DOM are assumed to be live meaning that
they are automatically updated when the underlying document is
changed.

实则,HTMLCollection 和 NodeList
万分相似,都是一个动态的因素集合,每一回访问都必要重新对文档举办查询。两者的原形上差距在于,HTMLCollection
是属于 Document Object Model HTML 规范,而 NodeList 属于 Document
Object Model Core
规范。
如此说有点难了然,看看上边的事例会相比好了解 [9]:

var ul = document.getElementsByTagName('ul')[0],
    lis1 = ul.childNodes,
    lis2 = ul.children;
console.log(lis1.toString(), lis1.length);    // "[object NodeList]" 11
console.log(lis2.toString(), lis2.length);    // "[object HTMLCollection]" 4

NodeList 对象会蕴藏文档中的所有节点,如 Element、Text 和 Comment 等。
HTMLCollection 对象只会蕴藏文档中的 Element 节点。
除此以外,HTMLCollection 对象比 NodeList 对象 多提供了一个 namedItem
方法。

从而在现世浏览器中,querySelectorAll 的重回值是一个静态的 NodeList
对象,而 getElementsBy 体系的重回值实际上是一个 HTMLCollection 对象 。

[1] Selectors API Level
2
[2] Document Object Model
Core
[3] http://jsbin.com/cuduyigi/1/edit?html,js,console
[4] http://jsbin.com/mabefihi/1/watch?html,js,console
[5]
Demo 1: http://jsbin.com/daduziba/1/watch?html,js,output
Demo 2: http://jsbin.com/xuvodipo/1/watch?html,js,output
[6] Selectors API Level
2
[7] Document Object Model
Core
[8] Document Object Model
HTML
[9] http://jsbin.com/qijivove/1/watch?html,js,console

网站地图xml地图