前阵子和伟大的JK同学学习了一下目前我们框架里新版本的selector,这里列的是第一版selector的代码思路。
后一版本调优性能,多了些函数,从性能上与各大框架比还是有竞争力的。
说句实在话,虽然各大框架和库都实现了selector。但看他们的selector实现其他的人看上去无疑都是难看懂。
而google,baidu上query出的结果基本都是说使用方式的文章,基本没有类似针对selector设计和具体实现上的文章。
所以,决定将整个思路和实现写出来,一来是增加印象,二来是给目前想写的人以参考。
我是以我学习及写selector的角度及把我向JK学习思路和我自己的设计,代码写的思路写出来。
这篇文章我也想不到写了这么长。建议这么看比较好:
- 不熟悉selector用户先去熟悉了休息会,再看此文;文中没有写详细的selector的具体内容,只是为了描述,大略的提了下;
- selector了解了之后再看看思路;顺序解析还是比较容易看懂的;
- 后文中的js代码里,我做了详细的注释,结构也和文中提的代码结构一样,有兴趣的同学可以读下,这个selector代码暂名为:Fox,接口为Fox.query(selector, context)。
代码可以点这里下载和测试。
此份代码已经注释,比较简单,我没去写优化的代码,之所以代码里面不写,是因为写了解释起来很绕,熟悉思路先吧,以后详细优化的文章及代码可以抽空再写。
OK,开始吧。
为什么有selector?
selector原来是用于CSS开发时方便样式与结构分离的策略。
而在如今做JS/DOM开发的时候,绝大部分的代码之一都是选择目标元素/集合。
在XML里有XPATH来实现该功能;同理的,在JS/DOM开发时自然出现了selector。
现在selector的火很大程度上除了需要感谢国家,还要感谢jquery。它如同当年Prototype带来了Ruby风格,一大批的前端开发人员都投入到jquery的怀抱。给了很多前端开发人员以快速上手,插件copy的方式来开发前端程序。
jquery是推进selector使用的催化剂。现在很多浏览器都支持了selector,但各实现都不尽相同,所以做一个适合自己的selector目前来看是有必要的。
selector简单实用,减少无技术含量的工作。
还可以重新约束一下前端的UI框架,在render接口不是耦合HTML结构,而是与CSS selector做为桥接
具体可以点这里可以看我之前写的一篇文章(降低HTML结构与脚本之间的强耦合),这里不再多述。
selector的应用接口
selector提供给外部的接口应该尽量遵循标准。开放的接口应该包括:
- document|element.querySelector(str)
- document|element.querySelectorAll(str)
举例说明:
var matches = document. querySelectorAll ( "div.note, div.alert" ) ;
具体在代码里的表现形式
Fox.query(selector, context);
selector及其类型
selector是一种选择DOM元素/集合的一种符号。它包括以下的类型:
- 包括通配选择符——*
- 类型选择符——如E { sRules }
- 属性选择符——它包含四种等式:
- E[attr] 选择具有 attr 属性的 E
- E[attr=value] 选择具有 attr 属性且属性值等于 value 的 E
- E[attr~=value] 选择具有 attr 属性且属性值为一用空格分隔的字词列表,其中一个等于 value 的 E 。这里的 value 不能包含空格
- E[attr|=value] 选择具有 attr 属性且属性值为一用连字符分隔的字词列表,由 value 开始的 E
- E[attr^=value] 选择具有 attr 属性开始的值为value的 E
- E[attr$=value] 选择具有 attr 属性结尾的值为value的 E
- E[attr*=value] 选择具有 attr 属性里包含value的E
- 包含选择符(祖先)——如E1 E2 选择所有被 E1 包含的 E2 。即 E1.contains(E2)==true 。
- 子对象选择符——如E1 > E2 选择所有作为 E1 子对象的 E2 。
- ID选择符——#ID { sRules } 以文档目录树(DOM)中作为对象的唯一标识符的 ID 作为选择符。
- 类选择符——E.className { sRules } ,它是属性选择符的一种简写形式。其效果等同于E [ class ~= className ] 。
- 伪类选择符——E : Pseudo-Classes { sRules } JS selector里取到的伪类有如下几种:
“first-child”,”last-child”, “only-child”,”nth-child”,”nth-last-child”,”first-of-type”,”last-of-type”,
“only-of-type”,”nth-of-type”,”nth-last-of-type”,”empty”,”parent”,
“not”,”enabled”,”disabled”,”checked”,”contains” - 伪对象选择符。E : Pseudo-Elements { sRules } 这在JS selector里可不实现(在DOM树里无法找到)
开发完的代码已支持的selector表
*
E
E F
E > F
E + F
E ~ F
E.warning
E#myid
E:first-child
E:last-child
E:nth-child(n)
E:nth-last-child(n)
E:only-child
E:enabled
E:disabled
E:checked
E:contains(“foo”)
E:not(s)
E[foo]
E[foo="bar"]
E[foo~="bar"]
E[foo^="bar"]
E[foo$="bar"]
E[foo*="bar"]
E[foo|="bar"]
使用示例:
- alert(Fox.query('div~div', document.body).length);
- alert(Fox.query('div~div.aa', document.body).length);
- alert(Fox.query('div span', document.body).length);
- alert(Fox.query('div div', document.body).length);
- alert(Fox.query('div