#nes nes is a javascript selector lib with incredible scalability, but still very fast
标准API有:
分别对应JS selector level 2的 querySelector、 querySelectorAll 与 matches (暂时浏览器还不支持)
返回 __第一个__匹配selector(在context的subtree中)的元素
返回 __所有__满足selector(在context的subtree中)的元素, 并按文档顺序排好
Arguments
- selector - 满足css选择器语法的字符串
- context(optional) - context限定节点查找的范围(缺省为document)
Example
nes.all("tr:nth-child(even) > td:nth-child(odd)") //-> 取得所有偶数列中奇数行
判断节点node是否满足特定的选择器selector
Arguments
- node - 目标节点
- selector - 满足css选择器语法的字符串
Example
如利用事件代理时,你不需要再去调用标准dom方法去测试节点是否满足某种条件,直接使用matches进行判断
container.addEventListener("click", function(e){
if(nes.matches(e.target, ".signup a.top")){//直接利用选择器判断是否是注册表单下的置顶按钮
//_onTop() ==> 处理逻辑
}
}
},false)
nes.js —— 40K(完整源码注释, 请压缩... gzip+minify 约3~4k)
- 直接插入
<script src="async.js"></script>
<script>
nes.one(...) //直接注册在全局
</script>
- NEJ
// 添加选择器适配模块({lib}util/query/query.js)的依赖, then
_v._$addEvent('#home > li', 'click', fn)
// 具体请参考http://nej.netease.com
- AMD
define(['/path/to/nes'], function(nes){
nes.all(...) // 方便
})
移步Wiki页
扩展是nes真正与众不同的部分到来, 使它即使在未来浏览器对querySelector API支持较好的情况下仍有存在价值。nes没有对规范外的选择器做支持, 而采用库外扩展的方式,部分扩展请参见extend目录
下面会以 场景描述>解决 的形式介绍这几种扩展,这些场景都是建立在即使浏览器已经实现了querySelector的前提下, 用来证明选择器扩展的价值所在
选择器扩展分为4类:
- 对伪类的扩展(pesudos)
- 对属性的扩展(operators)
- 对连接符的扩展(combos)
- 通过修改parser直接创建与id、pesudos这些等价的Simple Selector(parser)
Arguments
- name - 伪类名(类似selected、nth-child等)
- matcher(node, param) - 返回boolean值
- node - ,当前匹配到的节点,matcher返回这个节点是否满足要求
- param - 一个字符串代表匹配到的参数, 如nth-child(3)中的 3即为匹配到的参数
场景描述:
你需要获取所有的ul元素,这个元素中包含有满足(li.trigger a[href])的a标签
原始做法:
var lists = document.querySelectorAll("ul")
for(var i = lists.length; i--;){
var list = lists[i]
if(!list.querySelectorAll("li.trigger a[href]")){
lists.splice(i, 1)
}
}
return lists
理想做法:
nes.all('ul:include(li.trigger a[href])')
你需要做的扩展是:
// 其中node表示当前遍历到的节点, param代表pesudo的参数如本例的`li.trigger a[href]`
nes.pesudos("include", function(node, param){
return !!nes.one( param, node) // 返回bool值证明这个节点是否满足条件
})
###属性操作符扩展 —— nes.operators(String name, Function matcher)
- name - 伪类名(类似selected、nth-child等)
- matcher(String value, String nodeValue) - 返回boolean值判断这个节点是否满足要求, 参数有:
- value = 代表匹配到的属性值, 如[title=haha] 的haha
- nodeValue - 匹配到的节点真实属性值
场景描述
坑爹啊,标准selector竟然不提供__不等于__操作符的支持(!=),让我们用一行代码搞定它
理想做法
nes.all('div[class!=made_up]')
你需要做的扩展是
nes.operators("!=", function(node, key, value){
return node.getAttribute(key) !== value
})
- name - 伪类名(类似selected、nth-child等)
- matcher(String value, String nodeValue) - 返回boolean值判断这个节点是否满足要求, 参数有:
- value = 代表匹配到的属性值, 如[title=haha] 的haha
- nodeValue - 匹配到的节点真实属性值
__注意:__combo的扩展与上面两个扩展都不同,因为它是连接符而不是前两个的Simple Selector,它传入的是finder函数,目的是找到你满足的节点
场景描述: 你需要获得 ul.test li.trigger
节点 前的所有li节点(即连接符~
的相反版)
原生方法:
&$@&$&@($(!)!)##!&$^!@#$%^&(&^%$#@#$%^&()(%$!@#$% (真的很烦,你们可以私下去尝试下)
理想做法:
nes.all ('ul.test1 li.trigger & li') // =>向上第一个满足的兄弟节点
nes.all ('ul.test1 li.trigger + li') // =>上一个满足的直接兄弟节点
你需要做的扩展是:
// 这里直接一起扩展了~、+的相反版
nes.combos({
// 相当于 ~ 的相反版 , match是一个动态产生的方法,它代表这个节点,是否满足选择器条件,
// nes在match里封装了所有的递归操作,你无需考虑复杂的选择器匹配
// 但是你仍然要告诉nes,你要找的是哪个元素,比如~要做的是: 1)找到前面中的节点 2)
// 这个节点满足剩余的选择器,你在扩展里需要描述清楚的就是这个匹配的节点
"&":function(node,match){
while(node = node.nextSibling){
if(node.nodeType ===1 && match(node)){
return node // 如果节点是元素节点,并且满足match匹配规则
}
}
return null //如果没有则返回null,此轮匹配结束
},
// 与 + 相反
"%":function(node,match){
while(node = node.nextSibling){
if(node.nodeType ===1) return match(node)? node :null
}
}
})
这样做是为了提供给开发者最大的自由度和最小的代码开销(匹配逻辑都封装在了match这个运行时差生的函数)
nes在v0.05版本抽象出了parser部分,你可以通过parser来深层次的修改nes而不需要修改源代码, 具体请见parser的WIKI页
test case大部分来自Sizzle, 但是由于sizzle的设计并不是遵循规范的css selector 所以忽视部分在速度测试中sizzle不支持的选择器
sizzle目录剽窃了sizzle的速度测试用例,不能本地运行, 请祭起你的Server服务,推荐使用puer
test目录剽窃了Sizzle的test case (欠Sizzle的已然太多...)
Push前的 注意点:
-
修改前开个 __Issues__讨论下总是好的
-
docs
文件夹中我存放了注释详尽的docco文档,请先通览一次再进行有目的的修改 -
提交前请确认单元测试在IE6+(各种壳)以及其它现代浏览器是跑通的
-
对于Bug Fix 请先在测试的
index.html
尾部加入你的测试节点(id为 bug issues),千万不要删改其它test case的节点
Q.js、Sizzle、nwmatcher等前辈...还有百度UX那篇选择器扫盲贴。
nes.debug
: 不使用原生querySelectornes.nthCache.length
: 控制最大nth伪类参数的parse缓存,默认100
- v0.05 - 2013/1/4 抽象出了parser部分
- 我靠 是pseudo 不是pesudo