关于选择器最近选择器挺多,感觉这样编程的确很效率。于是研究了下选择器的实现。研究对象是 司徒正美 发布的选择器包 http://bbs.51js.com/thread-86703-1-1.html我们先说说选择器的主要技术点:
1. 选择器几乎都首先使用querySelectorAll,如果失败或者不存在这个方法,才会执行内部的动作。2. 在非IE浏览器下支持:
DOMAttrModified   标签属性修改时
DOMNodeInserted   标签插入时
DOMNodeRemoved    标签删除时但是document.write所创建的标签是无法被监视的,并且原身文件的HTML也无法被监视。他们只能激发JS操作对象产生的事件。
额外说明:
1 屏蔽querySelectorAll,直接替换所有文件的关键字querySelectorAll
已知明显BUG:
1. querySelectorAll是根据CSS规则来匹配的,如果你的页面中包含多个id,匹配#id, 那么大部分的选择器都会只返回第一个id标签,并且还会导致其他选择器的执行出现结果不正确。
   测试:首先必须屏蔽所有querySelectorAll,在 template.html 中写入标签 <div id="title"></div>,这时执行选择器 div[class!=example],除了query所有选择器结果都错误,多了一位。
2. querySelectorAll是根据CSS来匹配的,#title 会返回所有id为 title 的多个标签,选择器有Peppy、query、Sly,结果不统一,支持querySelectorAll就返回多个,不支持就返回第一个。
3. peppy、sizzle选择器在非IE浏览器中,在加载HTML时执行选择器,那么会创建缓存,而将来不激发DOMAttrModified、DOMNodeInserted、DOMNodeRemoved,那么缓存会一直存在,无法获取到HTML后来加载的标签。
4. EXT 对选择器 div ~ p 的匹配结果错误

解决方案 »

  1.   

    template.html 文件的测试代码推荐使用以下脚本。    function test(selector) {
                try {
                        var etext = ""
                       
                        var start = new Date().getTime();
                        var i = 1;
                        var fn = functionname.split('.');
                        var fun = window;
                        for (var deep = 0; deep < fn.length - 1; deep++)
                                fun = fun[fn[deep]];
                       
                        var dadaT = new Date().getTime()
                        i = 0
                        while ((++i)) {
                                var elements = fun[fn[deep]](selector);
                                if ( new Date().getTime() > (dadaT + 250) ) break
                        }
                       
                        var end = (new Date().getTime() - start) / i;
                        return { 'time': Math.round(end * 1000), 'found': get_length(elements) };
                } catch (err) {
                        if (elements == undefined) elements = { length: -1 };
                        var end = (new Date().getTime() - start) / i;
                        return ({ 'time': Math.round(end * 1000), 'found': get_length(elements), 'error': err });
                }
        }在非IE浏览器下,如果经常删除标签或者更改标签属性,Peppy和Sizzle的缓存模式几乎无效,执行效率低于其他所有选择器。
    而在传统网页环境选择器就是为了快速获取对象并且操作对象,而这两个选择器,只能说他们适合在测试环境下运行,但是不适合在传统环境下运行。并且他们在IE浏览器下的运行效率也不高。使用以下循环代码进行测试:    while (i++) {
                var elements = fun[fn[deep]](selector);
                if ( elements.length ) {
                        elements[0].setAttribute("test", "value")
                }
                if ( new Date().getTime() > (dadaT + 250) ) break
        }
        while (i++) {
                var elements = fun[fn[deep]](selector);
                if ( elements.length ) {
                        var aElement = document.createElement("DIV");
                        elements[0].appendChild(aElement)
                        aElement.parentNode.removeChild(aElement)
                }
                if ( new Date().getTime() > (dadaT + 250) ) break
        }
      

  2.   

    已知明显BUG:
    5. query , Sizzle, Sly 对重复标签的处理不正确,比如div, .subtoc
      

  3.   

    6. query不支持标签以下所有标签的属性选择器与伪类选择器,如div [href], div :empty
    7.yass、inQuery、Sizzle 对div :only-child获得的结果错误,应该获取div以下所有标签是父标签唯一子标签的标签
    8. Peppy 对 div:nth-child(-3n+10) 的执行结果错误,yass仅支持div:nth-child(odd)与div:nth-child(even),Sizzle、sky 对(-1n)执行出现无限循环。query在IE下返回的结果也不正确。(-3n+10)应返回序列0-10,并且序列%n返回0的。
    9.Peppy、yass、Sizzle、inQuery、EXT 在IE下直接使用选择器获取*,会发生错误,因为IE还返回!DOCTYPE、注译等元素,这些元素缺乏某些属性导致了选择器执行出错,如果其他子标签有注译,那么也会导致*号发生错误。