js框架开发之旅--选择器


我在幕后已经给我们的框架添加了许多功能,如果你想看到这些功能,就去我们的GitHub下载吧,turing.js.

这一章我们将讲解选择器的原理,比较分析一些流行的选择器的特性。选择器是js web框架重要的组成部分,值得我们将花比较多篇幅来讲解。


选择器的历史

提供一个跨平台的选择器接口,对于一个框架来说至关重要。不管是XPath式的还是CSS式的选择器,浏览器的支持都存在差异。
为了理解选择器的重要性,我们可以回到90年代,看看在没有js框架的时候,人们是怎么做的。
document.all    // A proprietary property in IE4
document.getElementById('navigation');
人们想到的第一件事是简化代码。Prototype通过$()方法做到了这些。
function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (Object.isString(element))
    element = document.getElementById(element);
  return Element.extend(element);
}
Prototype不是简单的给document.getElementById一个别名,它可以查询多个id,并且通过继承给元素赋予更多的功能。
我们正真需要的是getElementsBySelector。我们不仅仅想通过id和tagname检索元素,我们还要对元素进行一系列操作。我们在定义样式时,经常使用CSS选择器,因此我们在选择元素时也可以参考css选择器。
Simon Willison在2003年写了getElementsBySelector方法。这给我们对操作DOM结构提供了非常好的支持。
浏览器除了提供getElementById方法外,还提供了getElementsByClassName和getElementsByName等DOM查询方法。大部分非IE浏览器提供了XPath表达式的查询。
现在的浏览器已经提供了querySelector和querySelectorAll方法,这两个方法同样不能受到IE的支持(小牧注:IE8以上浏览器已经实现了querySelector和querySelectorAll方法)。


浏览器支持

Web开发人员对浏览器的差异感到非常苦恼,选择器是其中的重灾区。跨浏览器的选择器确实给Web开发人员减轻了不少的麻烦。
我曾经看到过一些处理浏览器bug的漂亮代码,像Sizzle中的一段代码:
// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
(function(){
  // We're going to inject a fake input element with a specified name
  var form = document.createElement("div"),
  id = "script" + (new Date()).getTime();
  form.innerHTML = "<a name='" + id + "'/>";
   
  // Inject it into the root element, check its status, and remove it quickly
  var root = document.documentElement;
  root.insertBefore( form, root.firstChild );
它创建了一个伪造的元素用来探测浏览器行为。浏览器的支持确实是一门非常考验程序员耐心的艺术。


性能

Javascript程序员频繁的使用选择器,查出在DOM结构任意位置的元素,因此选择器需要足够的块。
使用浏览器支持的原生选择器可以获取很好的性能, Sizzle使用querySelectorAll,但是不是所有的浏览器都支持该方法。
另一个办法是使用缓存,Sizzle和Prototype等框架都使用了缓存。

通过slickspeed或者Woosh这样的工具或类库可以测试选择器的性能。这些工具都非常有用,但是你对测试结果要小心。像Prototype和MooTools这样的库给元素继承了额外的方法,但是想Sizzle这样的纯选择器引擎没有这样做。这样的不同类型的框架应该区别对待。


其它的选择器引擎

我一直在参考Sizzle来给大家介绍选择器,其实还有更多的像Sizzle这样的选择器。去年受Sizzle发布的影响,接连出现了好几个类似的框架。自从出现以后,Sizzle一直受到框架开发者的欢迎。
Peppy借鉴了许多的类库,并且引入了一些有用的功能处理缓存。Sly也做了许多优化,并且允许你暴露选择器解析的过程。Peppy和Sly都是一个丰富的库,任何一点都不不比Sizzle差。


API设计

一般来说有两种API。一种是通过调用一个方法返回匹配的元素,并且把元素包装在自定义的类里,包装类可以给元素提供复杂的查询和操作方法。jQuery,Dojo和Glow就是这样做的。
jQuery通过$()方法,返回一个节点的列表,并且提供一个可链式调用的方法集。
Dojo通过dojo.query方法,返回一个类似数组的dojo.NodeList。Glow的glow.dom.get方法也有类似的功能。
第二种方法是直接返回继承了操作方法的元素列表,Prototype和MooTools就属于第二种。
Prototype使用$()方法代替getElementById,使用$$()方法来实现CSS或XPath规则的查询。他们都给查询的元素继承了自己提供的方法,都支持字符串和元素列表作为参数。
Turing设计了一个像Glow一样的类库,因此我们也采用Glow一样的方法设计我们的选择器接口。选择这个也是我出于自己的喜好,它能够提供一个包装在对象里的未经处理过的元素,这个包装帮我们屏蔽浏览器之间的操作差异。
turing.dom.find('.class')                  // return elements wrapped in a class without looking at each of them
.find('a')                                 // find elements that are links
.css({ 'background-color': '#aabbcc' })    // apply the style by actually processing elements

目标

因为Turing是一个为教学而生的框架,我们还是尽量让它保持简单:
  • 只支持CSS类型的选择器(可能在将来的版本或插件里支持XPath)
  • 有限的CSS伪类支持,我们会选择支持几个常用的伪类。
  • 尽量使用原生的方法,让代码越快越好。
  • 使用缓存提高性能。
  • 像Sly那样暴露解析结果。
  • 借鉴其他选择器引擎的处理浏览器问题的智慧。


结论

我希望你能够了解选择器的复杂性和重要性。如果仅仅是处理浏览器的缺陷,框架确实没有存在的必要。但是许多浏览器不是标准的浏览器,或者在迈向标准浏览器的过程中。我们要做的就是弥补这一部分的不足。

Sizzle是所有选择器引擎之母。我认为实现一个小巧的顺手的选择器,是件值的去做的事情。欢迎关注我们接下来的教程,我们将开始实现一个我们的选择器。


牧客网--让自由职业成为一个靠谱的工作


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值