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

Sizzle词法解析(中)

上一节我们处理分组选择器,这次我们看看剩余的2种处理情况。

关系处理器处理

在层级关系中有几种特殊的划分 Token : >, +, 空格, ~ 用来表明:父与子,兄弟,祖辈子孙之间的层级关系。

selector = 'div.aaron,div > p'

从 > 划分

rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" )

可以是>+~或者空白

这个分组是为了之后的关系选择确定。

if ( (match = rcombinators.exec( soFar )) ) {
    matched = match.shift();
    tokens.push({
        value: matched,
        // Cast descendant combinators to space
        type: match[0].replace( rtrim, " " )
    });
    soFar = soFar.slice( matched.length );
}

元素的匹配器:

Expr.filter :TAG, ID, CLASS, ATTR, CHILD, PSEUDO

通过一系列的正则抽出表达式中的内容。

ID:

///^#((?:\\.|[\w-] | [^\x00-\xa0] ) +)/
var characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+";
var ID = new RegExp("^#(" + characterEncoding + ")")

TAG:

var TAG =  new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" );

CLASS:

var Class = new RegExp( "^\\.(" + characterEncoding + ")" );

ATTR:

属性选择器有点复杂,通过第一次正则只能匹配器出整体,所以需要第二次分解,引入了Expr.preFilter,Expr.preFilter保留了3个兼容处理分别是ATTR,CHILD,PSEUDO复杂的选择器。

var identifier = characterEncoding.replace( "w", "w#" );
var attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
    // Operator (capture 2)
    "*([*^$|!~]?=)" + whitespace +
    // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
    "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
    "*\\]";

var ATTR = new RegExp( "^" + attributes );

preFilter: {
    "ATTR": function( match ) {
        match[1] = match[1].replace( runescape, funescape );
        // Move the given value to match[3] whether quoted or unquoted
        match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
        if ( match[2] === "~=" ) {
            match[3] = " " + match[3] + " ";
        }
        return match.slice( 0, 4 );
    }

任务

  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. //最简单的选择器
  32. var selector = 'div.aaron,div > p';
  33.  
  34. var filter = {
  35. CLASS: function(className) {},
  36. TAG: function(nodeNameSelector) {}
  37. }
  38.  
  39. var matchExpr = {
  40. CLASS: /^\.((?:\\.|[\w-]|[^\x00-\xa0])+)/,
  41. TAG: /^((?:\\.|[\w*-]|[^\x00-\xa0])+)/
  42. }
  43.  
  44. //层级选择器
  45. var rcombinators = /^[\x20\t\r\n\f]*([>+~]|[\x20\t\r\n\f])[\x20\t\r\n\f]*/;
  46.  
  47. var rtrim = /^[\x20\t\r\n\f]+|((?:^|[^\\])(?:\\.)*)[\x20\t\r\n\f]+$/g;
  48.  
  49. //sizzle的分组方式
  50. //分组
  51. var rcomma = /^[\x20\t\r\n\f]*,[\x20\t\r\n\f]*/;
  52. //TAG
  53. var TAG = /^((?:\\.|[\w*-]|[^\x00-\xa0])+)/;
  54.  
  55.  
  56. $('button').click(function(){
  57. var type;
  58. var soFar = selector;
  59. var match;
  60. var matched;
  61. var tokens;
  62. var groups = [];
  63.  
  64. while (soFar) {
  65.  
  66. //第一大块,分组关系
  67. //查找最左边的选择是不是逗号开头
  68. //matched用于处理第一进入
  69. //因为div input,div p 开始分解,第一个不是特殊符号
  70. if (!matched || (match = rcomma.exec(soFar))) {
  71. if (match) {
  72. // Don't consume trailing commas as valid
  73. soFar = soFar.slice(match[0].length) || soFar;
  74. }
  75. groups.push((tokens = []));
  76. }
  77.  
  78. //退出处理
  79. matched = false;
  80.  
  81. //第二大块,层级关系
  82. if ((match = rcombinators.exec(soFar))) {
  83. matched = match.shift();
  84. tokens.push({
  85. value: matched,
  86. type: match[0].replace(rtrim, " ")
  87. });
  88. soFar = soFar.slice(matched.length);
  89. }
  90.  
  91. //第三大块,选择器
  92. for (type in filter) {
  93. if ((match = matchExpr[type].exec(soFar))) {
  94. matched = match.shift();
  95. tokens.push({
  96. value: matched,
  97. type: type,
  98. matches: match
  99. });
  100. soFar = soFar.slice(matched.length);
  101. }
  102. }
  103.  
  104. if (!matched) {
  105. break;
  106. }
  107. }
  108.  
  109. alert(groups)
  110. })
  111.  
  112.  
  113.  
  114.  
  115.  
  116. </script>
  117.  
  118. </body>
  119. </html>
下一节