技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> CSS/HTML --> 一种基于匹配回朔的 css3 选择器引擎实现

一种基于匹配回朔的 css3 选择器引擎实现

浏览:2764次  出处信息

介绍

   CSS 选择器是一种应用于 DOM 节点查找场景的特定微型语法,

   本质上和正则表达式一样都是一种模式匹配语言,灵活使用可以方便得获取指定位置的节点集合。

   目前 W3C 推荐标准为 Selectors Level 3

   在 ie9+ 以及 firefox,chrome,mobile 等浏览器上原生有基本一致的实现,而在 ie 下则需要

   使用 javascript 模拟实现,本文介绍一种基于匹配回朔的 css3 选择器引擎实现,特定应用于 ie6,7,8 下。

语法

   css 选择器是一种紧凑的语法,根据 css3 规范一个选择器字符串首先由 ‘,’ 号分割的组组成,例如

s = g1,g2

   表示匹配 g1 与 g2 的元素集合。组内又由以 ‘ ‘,’+',’>’,’~’ 分割的简单选择器序列组成,例如

g1 = simple1 + simple2
g1 = simple1  simple2
g1 = simple1 > simple2
g1 = simple1 ~ simple2

   + 表示 simple1 匹配的元素与 simple2 的在同一层级,且 simple2 的元素紧跟在 simple1 后面。

   > 表示 simple2 匹配的元素紧跟在 simple1 的下一层级。

   ' ' 表示 simple1 匹配的元素比 simple2 的层级更靠近根节点。

   ~ 表示 simple1 匹配的元素与 simple2 的在同一层级,且位置靠前。

   简单选择器序列又可以由类型选择器以及后缀选择器组成,例如

simple1 = type_selector suffix_selector

   其中 typeselector 表示标签的名称,例如 ‘h1′,’h2′。不指定时默认为 ‘*’ 表示匹配任何标签。

   suffixselector 则一般用来进一步过滤,例如类选择器(限定类名),属性选择器(限定属性),伪类、伪元素等。

   例如 h1.x 匹配 <h1 class='x'> 而不匹配 <h1> 或 <span class='x'> 。

   完整语法描述可以查看 w3c 标准页面

   以下文章为了简单描述,将这种语法抽象为

a.b + c.d ~ e.f

   其中 a c e 为类型选择器,b d f 为后缀选择器,+ 代表直接位置关系的 > +,~ 代表模糊位置关系的 ~ ‘ ‘.

实现

解析器生成

   首先把 css 选择器语法用 LALR 解析程序生成器生成解析程序,从而可以把选择器的字符串格式转换成结构化的数据。

   这里采用 kison 来生成。

   对应 css 选择器语法的 kison 格式描述为:

   selector-grammar

   生成的解析器代码如下:

   parser.js

   流程图如下:

   解析器生成

   解析后的结构化数据为双向链表格式,例如

a.b + c.d

   解析后的链表为:

   linkedlist

引擎查找

   接下来的工作就是引擎查找,查找过程比较复杂,下面根据以下流程图结合实例讲解:

   engine

   举例选择器字符串为:

a.b + c.d ~ a + e.f

   匹配节点串为:

e.f a.b c.d e c.d e a e.f

获取种子集合

   和一般浏览器实现类似,采用自右向左的查找方法,首先要从最右端 的 type selector 获取到种子集合,根据本例为:

a e.f a.b c.d e c.d e a e.f
  ^           ^     ^   ^

选择器链表分组

   将选择器根据直接位置进行分组,以直接位置相连的简单的选择器序列为一组,分组后

a.b + c.d    ~     a + e.f
---------          -------

   分组的意义在于,每次匹配都以直接位置相连的组为单元做匹配,回朔时也应当以组为单元回朔(直接位置处回朔无意义)。

初步过滤种子

   根据最后的一组的选择器序列:

a + e.f

   进一步过滤种子集合,过滤后为:

a e.f a.b c.d e c.d e a e.f
  ^                     ^
  1                     2

进一步过滤种子

   这一步会根据对种子进行进一步过滤,过滤过程中甚至会发生回朔。

   例如对于第一个种子,在初步过滤后,节点串游标和选择器游标分别在

    a e.f a.b c.d e c.d e a e.f
   ^


    a.b + c.d    ~     a + e.f
            ^

   由于节点串游标已经越过节点串头,则表明该次匹配失败,该种子节点匹配失败。

   对于第二个种子,在初步过滤后,节点串游标和选择器游标分别在

        a e.f a.b c.d e c.d e a e.f
                            ^


        a.b + c.d    ~     a + e.f
                ^

   由于匹配失败,但选择器链接为 ‘~’ ,则可不移动选择器游标,而只移动节点串游标:

        a e.f a.b c.d e c.d e a e.f
                          ^


        a.b + c.d    ~     a + e.f
                ^

   可继续匹配到:

        a e.f a.b c.d e c.d e a e.f
                      ^


        a.b + c.d    ~     a + e.f
          ^

   此时由于选择器链接为 ‘+’ 因而移动节点串游标已经不可能再次匹配,此时应对选择器游标进行回朔到该分组前面:

        a e.f a.b c.d e c.d e a e.f
                      ^


        a.b + c.d    ~     a + e.f
                ^

   此时仍然匹配不成功,但可以移动节点串游标为:

        a e.f a.b c.d e c.d e a e.f
                    ^


        a.b + c.d    ~     a + e.f
                ^

   此时可以匹配选择器游标到头:

        a e.f a.b c.d e c.d e a e.f
          ^


        a.b + c.d    ~     a + e.f
       ^

   则表明该种子节点符合本次选择器串,最终匹配节点个数为 1

        a e.f a.b c.d e c.d e a e.f
                                ^

引擎代码

   引擎代码可参见: selector.js

单元测试

   单元测试直接拉取 sizzle 对应于 css3 的部分,经过少量调整,全部通过:

   selector - sizzle 测试

性能测试

   随便构造了一个稍显复杂的例子,比 sizzle 速度快不少:

   kissy-selector-sizzle

   欢迎提交新的例子。

建议继续学习:

  1. 前端必须掌握30个CSS3选择器    (阅读:4190)
  2. jQuery选择器探讨进阶    (阅读:3458)
  3. jQuery之find选择器    (阅读:3298)
  4. CSS选择器    (阅读:2887)
  5. 自己实现的简单的html元素选择器,类似jquery选择器,比jquery选择器还要快!    (阅读:2854)
  6. 推荐三十款CSS样式选择器代码    (阅读:2744)
  7. jQuery选择器对应的DOM API ——选择元素    (阅读:2235)
  8. 元素选择器 - Mini Query    (阅读:1165)
  9. IE7浏览器下CSS属性选择器二三事    (阅读:542)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
<< 前一篇:一览CSS布局标准
后一篇:CSS选择器 >>
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1