西红柿爱番茄

Feed Rss

更加DIY的selector查询DOM

08.11.2010, Javascript, by .

在上一篇文章中(谈谈松散耦合、颗粒度)提到的将javascript库或者框架更加向开发人员开放,DIY功能,尽量保持核心代码的精简和稳定,只开放接口,让开发人员根据特定的需求去DIY功能,而不是内定一整套方法集,供开发人员去使用。对此我例举了我写的query2.js为例子,这里就特别拿它出来说说。

query2中查询方式也是从左到右,这个是比较普通也容易实现的方式,有人说从右到左进行查询的话,效率会比较高,查询的复杂度较低。我想这就要开具体的selector了,如果是这样的“.test p”,那么从右到左的话复杂度就更高一些了,可能还得递归到document.body节点查询父元素的className是否等于test。所以双方面都有利有弊。

但是从左到右的查询方式还有一个比较苦恼的问题,就是“去重”(这是昨天跟瓶子吃饭的时候他提及到的问题),比如:

[html]
<div>
<div>
<p>Hello world</p>
</div>
</div>
[/html]

这时候如果使用“div p”来查询p标签元素的时候,如果不去重,就会导致使用getElementsByTagName查询到两个p元素,如果是在查询结果后给p标签添加事件,那么问题就大了。所以再进行查询的时候,必须得去重。

query2加入的去重的功能,同时还支持querySelectorAll(注意:对于不符合CSS指定的selector,querySelectorAll会报错),它最大的功能,就是可以DIY属于自己的selector,可以根据自己的需求来指定selector,具体示例可以查看谈谈松散耦合、颗粒度中给出的代码例子。源码展示如下:


[javascript]
;(function(g){
var D = document,fqueryAll=true;
var _tag = function(tag,p){
return p.getElementsByTagName(tag || "*");
}
var contain=function(a,b){
return a.contains ? a!=b && a.contains(b) : (a.compareDocumentPosition(b)==20);
};
var _queryMethod = {
"#":function(q,p){
var bits = q.split("#"),
tagName = bits[0],
id = bits[1],
element = document.getElementById(id);
return tagName && element.tagName.toLowerCase() != tagName ? [] : [element];
},
".":function(q,p){
var bits = q.split("."),
tagName = bits[0],
cn=bits[1],
elems = null,
returnEl = [],
index = 0,
reg = new RegExp("\\b"+cn+"\\b");
for(var i=0,l = p.length;i<l;i++){
elems = _tag(tagName,p[i]);
var tmp = null;
for(var j =0,m = elems.length;j<m;j++){
if(!/\S/.test((tmp = elems[j]).nodeValue)) continue;
if(reg.test(tmp.className)){
returnEl[index++] = tmp;
}
}
}
return returnEl;
},
"_tag_":function(q,p){
var found,returnEl = [],index=0;
for(var i=0,l=p.length;i<l;i++){
found = _tag(q,p[i]);
for(var j =0,m=found.length;j<m;j++){
returnEl[index++] = found[j];
}
}
return returnEl;
},
"]":function(q,p){
q.match(/^(.*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/);
var returnEl = [],
index=fIndex=0,
op=RegExp.$3,
tag=RegExp.$1,
attr=RegExp.$2,
attrvalue=RegExp.$4,
found = query(tag,p);

var checkFn = {
‘=’:function(e) { return (e.getAttribute(attr) == attrValue); },
‘~’:function(e) { return (e.getAttribute(attr).match(new RegExp(‘\\b’+attrValue+’\\b’))); },
‘|’:function(e) { return (e.getAttribute(attr).match(new RegExp(‘^’+attrValue+’-?’))); },
‘^’:function(e) { return (e.getAttribute(attr).indexOf(attrValue) == 0); },
‘$’:function(e) { return (e.getAttribute(attr).lastIndexOf(attrValue) == e.getAttribute(attr).length – attrValue.length); },
‘*’:function(e) { return (e.getAttribute(attr).indexOf(attrValue) > -1); }
}[op] || function(e) { return e.getAttribute(attr);};

for(var i=0,l=found.length;i<l;i++){
if(checkFn(found[i])){
returnEl[fIndex++] = found[i];
}
}
return returnEl;
}
}
//去重
var pureMutil = function(els){
var returnEl=[],index=0,tmp=els[0];
for(var i=1,l=els.length;i<l;i++){
if(!contain(tmp,els[i])){
returnEl[index++]=tmp;
if(i==l-1) {returnEl[index++]=els[l-1];break;}
}else if(i==l-1){
returnEl[index++]=els[i];
break;
}
tmp=els[i];
}
return returnEl;
}

g.query = function(q,p){
var elems = p || [D],reg=new RegExp(g.query.config.reg),tmp;
if(fqueryAll && D.querySelectorAll){
try{
return D.querySelectorAll(q);
}catch(e){fqueryAll=false;}
}
var tokens = q.split(‘ ‘),token,m;
for(var i=0,l=tokens.length;i<l;i++){
token = tokens[i];
m=token.match(reg);
tmp = _queryMethod[(m&&m[0]) || "_tag_"](token,elems);
if(l==1) {elems=tmp;break;}
elems = (i<l-1)? pureMutil(tmp) :tmp;
}
return elems;
}
g.query.config={
reg:"(\\])|(\\.)|(#)",
addSelector:function(mark,fn){
if(!mark || !fn){return;}
_queryMethod[mark]=fn;
mark = mark.replace(/(\.|\||\[|\]|\^|\\|\$|\?|\*|\+|\{|\}|\(|\))/g,"\\\\$1");
this.reg += this.reg.indexOf(mark)!=-1? "" : "|("+mark+")";
},
queryMethod:_queryMethod
}
})(this);
[/javascript]

更加DIY的selector查询DOM 有 10 条回应

  1. 内容很不错,已经rss订阅了,博主努力更新吧

  2. 学习资料http://www.xuexi2.com 谢谢博主分享!

  3. 嘿嘿,路过啦,很喜欢博主的博客。 Crazy1in.tk 留下脚印

  4. 多谢你的回访,如有兴趣可加友情链接

  5. 写的很好啊!!

  6. 网络因为你的文章而有声有色,生活因为有你才丰富多彩!

  7. 不错~~呵呵

  8. http://www.cne.cc 你好换友情连接吗?
    QQ29741五557

  9. 来看看,觉得你有点懒,博主都不怎么更新!

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>