源代码:
var isSelect = function(p/* path */, r/* root */) { //定义变量
var position = null;
var first = null;
var last = null;
var parentNode = null; //定义正则
var queueRegExp = null;
var indexRegExp = /(\/\/|\/)(\w+|\*)(?:\[(.*?)\])?(?:\/(\.+))?/g;
var replaceRegExp = /(@|\b)(.+?)(?: ?)($|\)|\&|\|)/g;
var replaceAttrRegExp = /(\w+)(\!\=|<\=|\=>|\=|<|>)?([^$]+)?/;
var replaceNumberRegExp = /^(?:\s+)?(\d+)(?:\s+)?$/;
var replaceSymbolRegExp = /\=>|\=/g;
var replacePositionRegExp = /position/g;
var replaceFirstRegExp = /first/g;
var replaceLastRegExp = /last/g; //定义集合
var queue = [];
var index = []; //定义函数
var queueSelect = function(e/* element */, i/* iterative */, p/* path */) { //判断迭代
if(index.length <= i) { //判断路径
if(queueRegExp.test(p)) { //定义差异路径
var _p = p.match(queueRegExp); //定义向上索引
var _i = index.slice(-1)[0].$4.length; //遍历迭代索引
for(var i = index.length - 1, j = e; 0 <= i; i--, j = j.parentNode) { if(index[i].$3 && !eval(index[i].$3.replace(replaceRegExp, function($1, $2, $3, $4) {return replaceSelect(j, index[i].$2, $2, $3, $4)}))) {
return;
} if(index[i].$1 === '//' && i > 0) {
for(var k = _p.pop().split('/').length; 0 < k; k--) {
j = j.parentNode;
}
} } //判断向上索引
if(_i) { for(var i = _i; 0 < i; i--) {
e = e.parentNode;
} for(var i = queue.length - 1; 0 <= i; i--) {
if(queue[i] === e) {
return;
}
} } //添加队列元素
queue.push(e); } } }; var indexSelect = function(e/* element */, i/* iterative */, p/* path */) { //参数赋值
i++;
p += '/' + e.tagName; if(e.nodeType === 1) { //队列选择
queueSelect(e, i, p); //遍历元素
for(var j = e.firstChild; j; j = j.nextSibling) {
indexSelect(j, i, p);
} }
}; var replaceSelect = function(e/* element */, t/* tag */, $1, $2, $3) { //判断行为
if($1 === '@') { //判断格式
if(replaceAttrRegExp.test($2)) { //定义属性值
var _$1 = e.getAttribute(RegExp.$1); //判断属性值
if(_$1 !== null) { //定义比较值
var _$3 = parseFloat(RegExp.$3) || RegExp.$3; //判断比较值
if(typeof _$3 === 'number') { _$1 = parseFloat(_$1); switch(RegExp.$2) {
case '=' : return (_$1 == _$3) + $3;
case '<' : return (_$1 < _$3) + $3;
case '>' : return (_$1 > _$3) + $3;
case '!=' : return (_$1 != _$3) + $3;
case '<=' : return (_$1 <= _$3) + $3;
case '=>' : return (_$1 >= _$3) + $3;
} } else { _$1 = _$1.toLowerCase(); switch(RegExp.$2) {
case '=' : return (_$1 == _$3 ) + $3;
case '<' : return (_$1 != _$3 && _$3.indexOf(_$1) > -1) + $3;
case '>' : return (_$1 != _$3 && _$1.indexOf(_$3) > -1) + $3;
case '!=' : return (_$1 != _$3 ) + $3;
case '<=' : return (_$1 == _$3 || _$3.indexOf(_$1) > -1) + $3;
case '=>' : return (_$1 == _$3 || _$1.indexOf(_$3) > -1) + $3;
} } } else {
return false + $3;
} } else {
return false + $3;
} } else { //判断赋值
if(e.parentNode === parentNode) {
position++;
} else {
position = 0;
first = 0;
last = -1;
parentNode = e.parentNode;
} //判断格式
if(replaceNumberRegExp.test($2)) {
return (RegExp.$1 == position) + $3;
} else { //计算表达式
$2 = eval($2
.replace(
replacePositionRegExp,
position
)
.replace(
replaceFirstRegExp,
first
)
.replace(
replaceLastRegExp,
function() {
if(last < 0) {
if(e === r) {
last = 0;
} else {
for(var i = parentNode.firstChild; i; i = i.nextSibling) {
if(i.nodeType === 1 && (i.tagName.toLowerCase() === t || t === '*')) {
last++;
}
}
}
}
return last;
}
)
.replace(
replaceSymbolRegExp,
function($) {
return $ === '=' ? '==' : '>=';
}
)
); //转换表达式
if(typeof $2 === 'number') {
$2 = $2 == position;
} return $2 + $3;
} } }; //索引赋值
while(indexRegExp.test(p.toLowerCase())) { index.push({
$1 : RegExp.$1,
$2 : RegExp.$2,
$3 : RegExp.$3,
$4 : RegExp.$4
}); queueRegExp = (queueRegExp || '') + (RegExp.$1 === '//' ? '\\/(.*?)\\/' : '\\/') + (RegExp.$2 === '*' ? '\\w+' : RegExp.$2); } //正则赋值
queueRegExp = new RegExp('^' + queueRegExp + '$', 'i'); //选择索引
indexSelect(r, 0, ''); //返回队列
return queue; };性能测试:
测试页中插入了 5000 多节点,参数筛选条件有 3 个(就是下面的例子),各浏览器的表现情况如下:
Internet Explorer 6(IETester) => 188 毫秒
Internet Explorer 8 => 157 毫秒
Firefox => 29 毫秒
Safari => 18 毫秒
Opera => 48 毫秒
Chrome => 35 毫秒
没有研究过别的选择器,也不知道这个测试结果相对来说是快还是慢,希望大牛们看看有什么地方可以优化的么。应用示例:
var $ = function() { var d = new Date();
var q = isSelect('//input[@type=button && @value=测试 && position = 1]', document.body); alert(new Date() - d); };语法说明:函数接收两个参数,而且都是必须的,用的时候可以写一个包装方法。第一个参数是路径(参照 xpath 语法的规范),第二个参数是搜索的容器节点。
var isSelect = function(p/* path */, r/* root */) { //定义变量
var position = null;
var first = null;
var last = null;
var parentNode = null; //定义正则
var queueRegExp = null;
var indexRegExp = /(\/\/|\/)(\w+|\*)(?:\[(.*?)\])?(?:\/(\.+))?/g;
var replaceRegExp = /(@|\b)(.+?)(?: ?)($|\)|\&|\|)/g;
var replaceAttrRegExp = /(\w+)(\!\=|<\=|\=>|\=|<|>)?([^$]+)?/;
var replaceNumberRegExp = /^(?:\s+)?(\d+)(?:\s+)?$/;
var replaceSymbolRegExp = /\=>|\=/g;
var replacePositionRegExp = /position/g;
var replaceFirstRegExp = /first/g;
var replaceLastRegExp = /last/g; //定义集合
var queue = [];
var index = []; //定义函数
var queueSelect = function(e/* element */, i/* iterative */, p/* path */) { //判断迭代
if(index.length <= i) { //判断路径
if(queueRegExp.test(p)) { //定义差异路径
var _p = p.match(queueRegExp); //定义向上索引
var _i = index.slice(-1)[0].$4.length; //遍历迭代索引
for(var i = index.length - 1, j = e; 0 <= i; i--, j = j.parentNode) { if(index[i].$3 && !eval(index[i].$3.replace(replaceRegExp, function($1, $2, $3, $4) {return replaceSelect(j, index[i].$2, $2, $3, $4)}))) {
return;
} if(index[i].$1 === '//' && i > 0) {
for(var k = _p.pop().split('/').length; 0 < k; k--) {
j = j.parentNode;
}
} } //判断向上索引
if(_i) { for(var i = _i; 0 < i; i--) {
e = e.parentNode;
} for(var i = queue.length - 1; 0 <= i; i--) {
if(queue[i] === e) {
return;
}
} } //添加队列元素
queue.push(e); } } }; var indexSelect = function(e/* element */, i/* iterative */, p/* path */) { //参数赋值
i++;
p += '/' + e.tagName; if(e.nodeType === 1) { //队列选择
queueSelect(e, i, p); //遍历元素
for(var j = e.firstChild; j; j = j.nextSibling) {
indexSelect(j, i, p);
} }
}; var replaceSelect = function(e/* element */, t/* tag */, $1, $2, $3) { //判断行为
if($1 === '@') { //判断格式
if(replaceAttrRegExp.test($2)) { //定义属性值
var _$1 = e.getAttribute(RegExp.$1); //判断属性值
if(_$1 !== null) { //定义比较值
var _$3 = parseFloat(RegExp.$3) || RegExp.$3; //判断比较值
if(typeof _$3 === 'number') { _$1 = parseFloat(_$1); switch(RegExp.$2) {
case '=' : return (_$1 == _$3) + $3;
case '<' : return (_$1 < _$3) + $3;
case '>' : return (_$1 > _$3) + $3;
case '!=' : return (_$1 != _$3) + $3;
case '<=' : return (_$1 <= _$3) + $3;
case '=>' : return (_$1 >= _$3) + $3;
} } else { _$1 = _$1.toLowerCase(); switch(RegExp.$2) {
case '=' : return (_$1 == _$3 ) + $3;
case '<' : return (_$1 != _$3 && _$3.indexOf(_$1) > -1) + $3;
case '>' : return (_$1 != _$3 && _$1.indexOf(_$3) > -1) + $3;
case '!=' : return (_$1 != _$3 ) + $3;
case '<=' : return (_$1 == _$3 || _$3.indexOf(_$1) > -1) + $3;
case '=>' : return (_$1 == _$3 || _$1.indexOf(_$3) > -1) + $3;
} } } else {
return false + $3;
} } else {
return false + $3;
} } else { //判断赋值
if(e.parentNode === parentNode) {
position++;
} else {
position = 0;
first = 0;
last = -1;
parentNode = e.parentNode;
} //判断格式
if(replaceNumberRegExp.test($2)) {
return (RegExp.$1 == position) + $3;
} else { //计算表达式
$2 = eval($2
.replace(
replacePositionRegExp,
position
)
.replace(
replaceFirstRegExp,
first
)
.replace(
replaceLastRegExp,
function() {
if(last < 0) {
if(e === r) {
last = 0;
} else {
for(var i = parentNode.firstChild; i; i = i.nextSibling) {
if(i.nodeType === 1 && (i.tagName.toLowerCase() === t || t === '*')) {
last++;
}
}
}
}
return last;
}
)
.replace(
replaceSymbolRegExp,
function($) {
return $ === '=' ? '==' : '>=';
}
)
); //转换表达式
if(typeof $2 === 'number') {
$2 = $2 == position;
} return $2 + $3;
} } }; //索引赋值
while(indexRegExp.test(p.toLowerCase())) { index.push({
$1 : RegExp.$1,
$2 : RegExp.$2,
$3 : RegExp.$3,
$4 : RegExp.$4
}); queueRegExp = (queueRegExp || '') + (RegExp.$1 === '//' ? '\\/(.*?)\\/' : '\\/') + (RegExp.$2 === '*' ? '\\w+' : RegExp.$2); } //正则赋值
queueRegExp = new RegExp('^' + queueRegExp + '$', 'i'); //选择索引
indexSelect(r, 0, ''); //返回队列
return queue; };性能测试:
测试页中插入了 5000 多节点,参数筛选条件有 3 个(就是下面的例子),各浏览器的表现情况如下:
Internet Explorer 6(IETester) => 188 毫秒
Internet Explorer 8 => 157 毫秒
Firefox => 29 毫秒
Safari => 18 毫秒
Opera => 48 毫秒
Chrome => 35 毫秒
没有研究过别的选择器,也不知道这个测试结果相对来说是快还是慢,希望大牛们看看有什么地方可以优化的么。应用示例:
var $ = function() { var d = new Date();
var q = isSelect('//input[@type=button && @value=测试 && position = 1]', document.body); alert(new Date() - d); };语法说明:函数接收两个参数,而且都是必须的,用的时候可以写一个包装方法。第一个参数是路径(参照 xpath 语法的规范),第二个参数是搜索的容器节点。
\\ 连个斜线代表子孙节点isSelect('/body/div', document.body);上边的意思是查找 body 下边的 div ,可以写成下边这样直接查找子孙节点:
isSelect('//div', document.body);也可以查找子孙的子孙
isSelect('//div//span', document.body);还可以添加条件
isSelect('//div[@name=myname]//span', document.body);多个条件同时使用也可以
isSelect('//div[(@name=myname1 || @name=myname2) && @innerhtml>你好]//span', document.body);上边条件“@innerhtml>你好”中,我使用的是大于号(<)。意思是 innerhtml 属性的值包含“你好”。下边是所有可以使用的运算符:
= 相等
< 数字:右边大于左边,字符串:右边包含左边
> 数字:左边大于右边,字符串:左边包含右边
!= 不相等
<= 数字:右边大于等于左边,字符串:右边包含左边或相等
=> 数字:左边大于等于右边,字符串:左边包含右边或相等在进行属性对比的时候,函数会先尝试将对比值转换成数字做数学比较,如果转换失败才会执行字符串比较。例如:
isSelect('//div[@id>12]'); //条件中的 12 可以转换成数字。除了属性对比还可以使用位置对比
isSelect('//div[0]'); //找到第 1 个
isSelect('//div[position < 100]'); //找到前 100 个
isSelect('//div[position % 5 = 0]'); //找到位置与 5 取余等于 0 的
isSelect('//div[first]'); //找到第 1 个
isSelect('//div[last - 3]'); //找到倒数第 3 个
isSelect('//div[@id=mydiv]/.'); //从结果中向上查找 1 级
isSelect('//div[@id=mydiv]/..'); //从结果中向上查找 2 级
isSelect('//div[@id=mydiv]/...'); //从结果中向上查找 3 级
isSelect('//div[@id=mydiv]/....'); //从结果中向上查找 4 级
只是一个建议
你還準備出框架,我早就出了n多時間了
http://topic.csdn.net/u/20120206/16/662e1010-ab19-4c7d-8abe-708f9d0697bf.html
唉,我发现我看错了,连“return this” 都不知道写,看来连链式调用都算不上,垃圾中的垃圾……
你的代码:
$("#sp").css({width:"100px",height:"100px",border:"1px solid red"});而且你说就只知道抄 jq 的,知道什么叫用户体验么?你当所有美工都能写出正确的对象格式来?你敢叫参数这样发送么?你行么你?
$("#sp").css("width:100px; height:100px; border:1px solid red;");
楼主这个可以放到firefox里让ff支持xpath选择器了...
重新封装一下, 能完全兼容opera的xpath语法就好了..
那样就可以把用到xpath的opera-ujs无缝移植到ff的gm上了..
楼主这个可以放到firefox里让ff支持xpath选择器了...
重新封装一下, 能完全兼容opera的xpath语法就好了..
那样就可以把用到xpath的opera-ujs无缝移植到ff的gm上了..