7-14 Sizzle超级匹配器(下)
本节编程练习不计算学习进度,请电脑登录imooc.com操作

Sizzle超级匹配器(下)

这是第一组终极匹配器的生成流程了,可见过程极其复杂,被包装了三层,依次:

addCombinator
elementMatcher
Expr.relative

三个方法嵌套处理出来的结构:

然后继续分解下一组,遇到关系选择器又继续依照以上的过程分解,但是有一个不同的地方,下一个分组会把上一个分组给一并合并了。

所以整个关系就是一个依赖嵌套很深的结构,最终暴露出来的终极匹配器其实只有一个闭包,但是有内嵌很深的分组闭包了,依照从左边往右依次生成闭包,然后把上一组闭包又push到下一组闭包。

就跟栈是一种后进先出的数据结构一样处理了,所以在最外层也就是:

type=["checkbox"]

我们回到superMatcher方法的处理了,在遍历seed种子合集,依次匹配matchers闭包函数,传入每一个seed的元素与之匹配(这里就是input),在对应的编译处理器中通过对input的处理,找到最优匹配结果:

function( elem, context, xml ) {
    var i = matchers.length;
    while ( i-- ) {
        if ( !matchers[i]( elem, context, xml ) ) {
            return false;
        }
    }
    return true;
} :

这里注意了,是i--,从后往前找,所以第一次开始匹配的就是:

check: "checkbox"
name: "type"
operator: "="

那么就找到对应的Attr处理方法:

Sizzle.attr( elem, name )

传入elem元素就是seed中的input元素,找到是否有'type'类型的属性,比如:

<input type="text">"

所以第一次匹配input就出错了,返回的type是text,而不是我们需要的'checkbox',这里返回的结果就是false,所以整个之后的处理就直接return了,继续拿出第二个input。

继续上一个流程,这时候发现检测到的属性:

var result = Sizzle.attr( elem, name );
result: "checkbox"

此时满足第一条匹配,然后继续 i = 0

!matchers[i]( elem, context, xml )

找到第0个编译函数:

addCombinator

如果是不紧密的位置关系,那么一直匹配到true为止,如祖宗关系的话,就一直找父亲节点直到有一个祖先节点符合规则为止。

直接递归调用:

matcher( elem, context, xml )

其实就是下一组闭包队列了,传入的上下文是 div.aaron,也就是<input type="checkbox">的父节点:

function (elem, context, xml) {
                var i = matchers.length;
                //从右到左开始匹配
                while (i--) {
                    //如果有一个没匹配中,那就说明该节点elem不符合规则
                    if (!matchers[i](elem, context, xml)) {
                        return false;
                    }
                }
                return true;
        }

依照上面的规则,这样递归下去了,一层一层的匹配,可见它原来不是一层一层往下查,却有点倒回去向上做匹配、过滤的意思。Expr里面只有find和preFilter返回的是集合。

尽管到这里暂时还带着一点疑问,但是我想Sizzle最基本的“编译原理”应该已经解释清楚了。

任务

  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.  
  11. <button id="test1">超级匹配器,点击选中checked</button>
  12.  
  13. <div id="text">
  14. <div class="Aaron">
  15. <input type="checkbox" name="readme" />
  16. <input type="checkbox" name="ttt" />
  17. <input type="checkbox" name="aaa" />
  18. <p>Sizzle</p>
  19. </div>
  20. </div>
  21.  
  22.  
  23. <script type="text/javascript">
  24.  
  25. var filter = {
  26. ATTR: function(name, operator,check) {
  27. return function(elem) {
  28. var attr = elem.getAttribute(name)
  29. if (operator === "=") {
  30. if(attr === check){
  31. return true
  32. }
  33. }
  34. return false;
  35. }
  36. },
  37. TAG: function(nodeNameSelector) {
  38. return function(elem) {
  39. return elem.nodeName && elem.nodeName.toLowerCase() === nodeNameSelector;
  40. };
  41. }
  42. }
  43.  
  44.  
  45. function addCombinator(matcher) {
  46. return function(elem, context, xml) {
  47. while ((elem = elem['parentNode'])) {
  48. if (elem.nodeType === 1) {
  49. //找到第一个亲密的节点,立马就用终极匹配器判断这个节点是否符合前面的规则
  50. return matcher(elem);
  51. }
  52. }
  53. }
  54. }
  55.  
  56.  
  57. function elementMatcher(matchers) {
  58. return matchers.length > 1 ?
  59. function(elem, context, xml) {
  60. var i = matchers.length;
  61. while (i--) {
  62. if (!matchers[i](elem, context, xml)) {
  63. return false;
  64. }
  65. }
  66. return true;
  67. } :
  68. //单个匹配器的话就返回自己即可
  69. matchers[0];
  70. }
  71.  
  72.  
  73.  
  74. function matcherFromTokens(tokens){
  75. var len = tokens.length;
  76. var matcher, matchers = [];
  77. for (i = 0; i < len; i++) {
  78. if (tokens[i].type === " ") {
  79. matchers = [addCombinator(elementMatcher(matchers), matcher)];
  80. } else {
  81. matcher = filter[tokens[i].type].apply(null, tokens[i].matches);
  82. matchers.push(matcher);
  83. }
  84. }
  85. return elementMatcher(matchers);
  86. }
  87.  
  88.  
  89. /**
  90. * 超级匹配器
  91. * @return {[type]} [description]
  92. */
  93. function matcherFromGroupMatchers(elementMatchers) {
  94. var superMatcher = function(seed) {
  95. var results = [];
  96. var matcher, elem;
  97. for (var i = 0; i < seed.length; i++) {
  98. matcher = elementMatchers[0];
  99. var elem = seed[i];
  100. if (matcher(elem)) {
  101. results.push(elem);
  102. break;
  103. }
  104. }
  105. return results;
  106. };
  107. return superMatcher;
  108. }
  109.  
  110.  
  111.  
  112.  
  113. function compile() {
  114. //种子合集
  115. var seed = document.querySelectorAll('input')
  116. //选择器
  117. var selector = "Aaron [name=ttt]";
  118. var elementMatchers = [];
  119. var match = [{
  120. matches: ["div"],
  121. type: "TAG",
  122. value: "Aaron"
  123. }, {
  124. type: " ",
  125. value: " "
  126. }, {
  127. matches: ["name", "=", "ttt"],
  128. type: "ATTR",
  129. value: "[name=ttt]"
  130. }]
  131.  
  132. elementMatchers.push(matcherFromTokens(match));
  133.  
  134.  
  135. //超级匹配器
  136. var cached = matcherFromGroupMatchers(elementMatchers)
  137. results = cached(seed)
  138.  
  139. results[0].checked = 'checked'
  140. }
  141.  
  142.  
  143. $('#test1').click(function() {
  144. compile();
  145. })
  146.  
  147.  
  148.  
  149.  
  150.  
  151. </script>
  152.  
  153. </body>
  154. </html>
返回课程