7-6 Sizzle词法解析(下)
本节编程练习不计算学习进度,请电脑登录imooc.com操作

Sizzle词法解析(下)

如果选择器是 div.aaron input[name=ttt],div p,之前通过词法解析出来的的七类型:

TAG、>、TAG、CLASS、"空格"、"TAG"、ATTR

如下面的结构所示:

type: "TAG"
value: "div" 
matches ....

type: ">"
value: " > "

type: "TAG"
value: "p"
matches ....
除去关系选择器,其余的有语意的标签都对应这分析出matches。
tokenize最后一个属性选择器分支单元结构。
"[input[name=ttt]]"
matches = [
   0: "type"
   1: "="
   2: "ttt"
]
type: "ATTR" 
value: [name=ttt]"

那么我们从右到左边开始匹配最终合集单元。

从左边开始很明显是属性选择器:

input[name=ttt]

但是这个东东原生的API是不认识的,所以我们只能再往前找input的合集:

type: "TAG"
value: "input"

这种标签Expr.find能匹配到了,所以直接调用:

Expr.find["TAG"] = support.getElementsByTagName ?
    function(tag, context) {
        if (typeof context.getElementsByTagName !== strundefined) {
            return context.getElementsByTagName(tag);
        }
} :

但是getElementsByTagName方法返回的是一个合集。

这里引入了seed - 种子合集(搜索器搜到符合条件的标签),放入到这个初始集合seed中。这种我们找到了最终的一个合集,那么我们需要的就是根据剩余的条件筛选出真正的选择器就OK了,这里暂停了,不再往下匹配了,如果再用这样的方式往下匹配效率就慢了。

开始整理

重组一下选择器,剔掉已经在用于处理的tag标签,input,所以选择器变成了:

selector:"div > div.aaron [name=ttt]"

这里可以优化下,如果直接剔除后,为空了,就证明满足了匹配要求,直接返回结果了。

到这一步为止,我们能够使用的东东:

1、seed合集

2、通过tokenize分析解析规则组成match合集,本来是7个规则快,因为匹配input,所以要对应的也要踢掉一个所以就是6个了。

3、选择器语句,对应的踢掉了input。

selector:"div > div.aaron [name=ttt]"

此时send目标合集有2个最终元素了,那么如何用最简单,最有效率的方式从2个条件中找到目标呢?

这个问题后面小节将给你们揭晓。

任务

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  5. <script src="http://code.jquery.com/jquery-latest.js"></script>
  6. <title></title>
  7. </head>
  8. <body>
  9.  
  10. <button>sizzle获取到种子集合</button>
  11.  
  12. <div id="text">
  13. <div class="aaron">
  14. <input type="checkbox" name="readme" />
  15. <input type="checkbox" name="ttt" />
  16. <input type="checkbox" name="aaa" />
  17. <p>慕课网</p>
  18. </div>
  19. </div>
  20.  
  21. <div>
  22. <input type="checkbox" name="readme" />
  23. <input type="checkbox" name="ttt" />
  24. <input type="checkbox" name="aaa" />
  25. <p>Aaron</p>
  26. </div>
  27.  
  28.  
  29. <script type="text/javascript">
  30.  
  31. var selector = 'div.aaron input[name=ttt]';
  32.  
  33. var Expr = {
  34. relative : {
  35. ">": { dir: "parentNode", first: true },
  36. " ": { dir: "parentNode" },
  37. "+": { dir: "previousSibling", first: true },
  38. "~": { dir: "previousSibling" }
  39. },
  40. find: {
  41. CLASS: function(className, context) {},
  42. ID: function(id, context) {},
  43. TAG: function(tag, context) {
  44. return document.getElementsByTagName(tag);
  45. },
  46. ATTR:function(){}
  47. }
  48. }
  49.  
  50. var match = [{
  51. matches: ["div"],
  52. type: "TAG",
  53. value: "div"
  54. }, {
  55. matches: ["aaron"],
  56. type: "CLASS",
  57. value: ".aaron"
  58. }, {
  59. type: " ",
  60. value: " "
  61. }, {
  62. matches: ["input"],
  63. type: "TAG",
  64. value: "input"
  65. }, {
  66. matches: ["name"],
  67. type: "ATTR",
  68. value: "[name=ttt]"
  69. }];
  70.  
  71.  
  72. function toSelector(tokens) {
  73. var i = 0,
  74. len = tokens.length,
  75. selector = "";
  76. for (; i < len; i++) {
  77. selector += tokens[i].value;
  78. }
  79. return selector;
  80. }
  81.  
  82.  
  83. $('button').click(function(){
  84.  
  85. var results = [];
  86. var i = match.length
  87.  
  88. while (i--) {
  89. token = match[i];
  90. if (Expr.relative[(type = token.type)]) {
  91. break;
  92. }
  93. if ((find = Expr.find[type])) {
  94. if ((seed = find(token.matches[0]))) {
  95. match.splice(i, 1);
  96. selector = seed.length && toSelector(match);
  97. results.push(seed);
  98. break;
  99. }
  100. }
  101. }
  102.  
  103. alert('选择器 '+selector)
  104. alert('seed种子合集 '+results[0])
  105. })
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117. </script>
  118.  
  119. </body>
  120. </html>
下一节