搜尋

首頁  >  問答  >  主體

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

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

巴扎黑巴扎黑2909 天前324

全部回覆(4)我來回復

  • 巴扎黑

    巴扎黑2017-04-10 14:39:25

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

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

    第一步,解析

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

    1

    2

    <code class="lang-javascript">X('#header .nav ul');

    </code>

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

    1

    2

    3

    4

    5

    6

    <code class="lang-javascript">[

        {type: 'id', value: 'header'},

        {type: 'class', value: 'nav'},

        {type: 'tag', value: 'ul'}

    ]

    </code>

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

    第二步,查询

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

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

    1

    2

    3

    4

    5

    6

    7

    <code class="lang-javascript">var handlers = {

        'id' : function (el, value) {

            return el.getElementById(value);

        },

        ...

    };

    </code>

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

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

    回覆
    0
  • 高洛峰

    高洛峰2017-04-10 14:39:25

    把jQuery的抄一遍是极好的 ( ͡° ͜ʖ ͡°)

    回覆
    0
  • 黄舟

    黄舟2017-04-10 14:39:25

    这篇文章很好的回答了你的问题,推荐:

    Efficiently Rendering CSS

    回覆
    0
  • PHPz

    PHPz2017-04-10 14:39:25

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

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    77

    78

    79

    80

    81

    82

    83

    84

    85

    86

    87

    88

    89

    90

    91

    92

    93

    94

    <code class="lang-Javascript"><br>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;

    }

    </code>

    回覆
    0
  • 取消回覆