首页 >社区问答列表 >javascript - 前端如何写出高效选择器?

javascript - 前端如何写出高效选择器?

css也好jq也好?
怎么样的选择器是高效的?

  • 巴扎黑
  • 巴扎黑    2017-04-10 14:39:254楼

    首先,我要说没必要来实现选择器这种轮子,虽然我不反对造轮子,但选择器这种轮子已经非常成熟了,而且现代浏览器已经内置了选择器。

    不过如果你坚持还是要继续的话,我可以简单探讨下。顺便说一下,jquery的选择器用的是sizzle,它以前用的是自己写的,不过后来大概也觉得这个轮子没啥意思。。。

    第一步,解析

    首先要把你的查询字符串解析成查询链,这个过程简单但是繁杂,因为除了常见的css选择器,还有各种伪类。我们就拿最简单的一个查询来举例子把,我把我们的选择器叫做X

    X('#header .nav ul');
    

    这段代码经过我们的解析后会变成类似这样的结构

    [
        {type: 'id', value: 'header'},
        {type: 'class', value: 'nav'},
        {type: 'tag', value: 'ul'}
    ]
    

    OK,这样一个简单的查询链就出来了,理论上我们按照这个顺序一步一步就可以得到期望的结果了。

    第二步,查询

    注意,如果你没有用querySelector这个函数,那么基本上就是利用 getElementById, getElementsByName, getElementsByTagName, getElementsByClassName 这几个函数来实现了

    我们可以把上面查询链的type给映射到具体的操作,类似

    var handlers = {
        'id' : function (el, value) {
            return el.getElementById(value);
        },
        ...
    };
    

    最后,我们遍历这条查询链,根据每个节点的type来查询value,然后把每个节点结果作为下一个查询的el,依此类推

    注意,以上只是做一个选择器的基本原理,实际情况要复杂的多

    +0添加回复

  • 回复
  • PHPzhong
  • PHPzhong    2017-04-10 14:39:251楼

    以前不知道瀏覽器有 querySelector,所以自己寫了一個,不過功能不全。
    額外的好處是修改一下也可以用來創建元素(類似 Emmet)。
    效率肯定不如瀏覽器自帶的。


    function $(x) { var s = (function(t) { var s = { tagName: "", id: "", classes: [], attributes: [] }, p = [], i, j; var m = { "]" : "[" }, n = false; for (i = t.length - 1, j = t[i]; i >= 0; j = t[--i]) { if (!n) { switch (j) { case ".": s.classes.push(p.join("")); p = []; break; case "#": s.id = p.join(""); p = []; break; case "]": n = true; p = []; break; default: p.unshift(j); } } else { switch (j) { case "[": s.attributes.push(p.join("")); p = []; n = false; break; default: p.unshift(j); } } } s.tagName = (p.join("")); //alert(s.tagName + ", #" + s.id + ", ." + s.classes.join(", .")); return s; }(x)); var y = []; if (s.id) y = [document .getElementById(s.id)] .filter(function(v) { if (s.tagName) return v.tagName === s.tagName.toUpperCase(); return true; }); else if (s.tagName) y = (Array.prototype.slice.call(document .getElementsByTagName(s.tagName))); else if (s.classes.length > 0 || s.attributes.length > 0) if (!y || !y.length > 0) y = Array.prototype.slice.call(document .getElementsByTagName('*')); if (s.classes.length > 0) y = y.filter(function(v) { var c = v.className.split(" "); return s.classes.every(function(n) { return c.indexOf(n) !== -1; }); }); if (s.attributes.length > 0) y = y.filter(function(v) { return s.attributes.every(function(n) { n = n.split("="); var attributeName = n[0].trim(); if (v.hasAttribute(attributeName)) if (n.length === 1) return true; else { return v.getAttribute(attributeName) === n[1].trim().replace(/^"|"$/g, ''); } return false; }); }); return y; }

    +0添加回复

  • 回复