JavaScript选择器有很多,大到sizzle小到mini,再加上各种框架各种库,可以说高低胖瘦各有不同。一直以来都想亲手做一个选择器,虽说现成的轮子到处都有,但不懂造轮子的前端不是好攻城师啊。可是无奈精力有限,而且现成的轮子都很好使,这个想法就被一拖再拖。
闲话不多说...
选择器的原理大致如下:
- 分析得到的 selector 文本,如果是分组的选择器则拆开;
- 根据 selector 从左向右依次查询,然后去重(或从右向左依次过滤,不需要去重);
- 对剩余的选择器组执行第2步,合并结果;
- 结果去重。
我的轮子设计如下:
- 将得到的 selector 文本解析为令牌数组及对应的参数数组;
- 根据令牌生成查询语句串并缓存,以备重复使用;
- 执行查询语句串,返回结果。
可以看出重点在查询语句串的生成,查询顺序计划采用分部查询,而不是单纯的从右向左。
根据设计先做出 selector 令牌解析器:http://dishuostec.sinaapp.com/javascript/css_token/
解析器获取 selector 选择器然后解析,返回一个长度为2的数组 T,T[0]为令牌数组,T[1]为参数数组。
示例:
选择器 | 令牌 | 参数 |
---|---|---|
#title | [ID] | ['title'] |
div[class] | [TYPE, ATTR_HAS] | ['div', class] |
div[class=example] | [TYPE, ATTR_MATCH] | ['div', ['class', 'example']] |
div[class^=exa][class$=mple] | [TYPE, PREFIXMATCH, SUFFIXMATCH] | ['div', ['class', 'exa'], ['class', 'mple']] |
ul .tocline2 | [TYPE, CONBI_DESCENDANT, CLASS] | ['ul', null, tocline2] |
body div | [TYPE, CONBI_DESCENDANT, TYPE] | ['body', null, 'div'] |
div > p | [TYPE, CONBI_CHILD, TYPE] | ['div', '>', 'p'] |
div ~ p | [TYPE, CONBI_GENERAL_SIBLING, TYPE] | ['div', '~', 'p'] |
div, p, a | [TYPE, GROUP, TYPE, GROUP, TYPE] | ['div', ',', 'p', ',', 'a'] |
h1#title + div > p | [TYPE, ID, CONBI_ADJACENT_SIBLING, TYPE, CONBI_CHILD, TYPE] | ['hi', 'title', '+', 'div', '>', 'p'] |