源代码:
  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 语法的规范),第二个参数是搜索的容器节点。

解决方案 »

  1.   

    一些示例:\ 一个斜线代表子节点
    \\ 连个斜线代表子孙节点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 个
      

  2.   

    还可以在最后加上向上索引isSelect('//div[@id=mydiv]/...');上边在最后加上的“/...”,意思是找到符合条件节点的父元素,斜杠后边有几个点(.),就代表向上几级例如:
    isSelect('//div[@id=mydiv]/.');  //从结果中向上查找 1 级
    isSelect('//div[@id=mydiv]/..');  //从结果中向上查找 2 级
    isSelect('//div[@id=mydiv]/...');  //从结果中向上查找 3 级
    isSelect('//div[@id=mydiv]/....');  //从结果中向上查找 4 级
      

  3.   

    测试地址:http://www.zhanghong.name/test/isselect.htm
      

  4.   

    个人认为要高效的话,需要动态生成函数,把path解析成一系列高效的函数,而不是满地正则。
    只是一个建议
      

  5.   

    有什么用啊,,搞这么复杂,无非就是一个节点选择器嘛,,为什么不直接赋个id,然后document.getElementById获取,你这种写法的随意性,会导致自身的javascript知识混乱,
      

  6.   

    你真逗,那你说 sizzle 有什么用,找喷是么?
      

  7.   

    没事写这东西干什么,jquery不是很好用吗。
      

  8.   


    你還準備出框架,我早就出了n多時間了
    http://topic.csdn.net/u/20120206/16/662e1010-ab19-4c7d-8abe-708f9d0697bf.html
      

  9.   

    你内也叫框架,要你这么说我的框架也就早了,而且都好版了就你那破玩意能查dom自定义的属性值么?能根据条件运算么?回去好好补补设计模式在来蛋B,懂什么叫装饰着模式?你那顶多就是链式调用函数,什么破玩意。
      

  10.   


    唉,我发现我看错了,连“return this” 都不知道写,看来连链式调用都算不上,垃圾中的垃圾……
      

  11.   


    你的代码:
    $("#sp").css({width:"100px",height:"100px",border:"1px solid red"});而且你说就只知道抄 jq 的,知道什么叫用户体验么?你当所有美工都能写出正确的对象格式来?你敢叫参数这样发送么?你行么你?
    $("#sp").css("width:100px; height:100px; border:1px solid red;");
      

  12.   

    opera9开始就支持xpath的...可以直接写...
    楼主这个可以放到firefox里让ff支持xpath选择器了...
    重新封装一下, 能完全兼容opera的xpath语法就好了..
    那样就可以把用到xpath的opera-ujs无缝移植到ff的gm上了..
      

  13.   

    opera9开始就支持xpath的...可以直接写...
    楼主这个可以放到firefox里让ff支持xpath选择器了...
    重新封装一下, 能完全兼容opera的xpath语法就好了..
    那样就可以把用到xpath的opera-ujs无缝移植到ff的gm上了..
      

  14.   

    我的选择器参考了 xpath 的语法,但是又结合了我自己一些思路,虽然像 xpath 但又不一样。用的时候可以自己定义一些包装函数,比如可以叫包装函数实现一些定式,比如:.id #class 之类的。