zoukankan      html  css  js  c++  java
  • jQuery Sizzle选择器(一)

    1、浏览器对css选择器采取逆向(从右向左)解析的原因:

      如果正向解析,例如「div div p em」,我们首先就要检查当前元素到 html 的整条路径,找到最上层的div,再往下找,如果遇到不匹配就必须回到最上层那个 div,往下再去匹配选择器中的第一个 div,回溯若干次才能确定匹配与否,效率很低。

      逆向匹配则不同,如果当前的 DOM 元素是 div,而不是 selector 最后的 em,那只要一步就能排除。只有在匹配时,才会不断向上找父节点进行验证。找到所有的em之后,再通过查找他的父元素是不是p来进行过滤。

    2、Sizzle如果分解用户传入的css选择器字符串

    以”div > div.cl p span.red“为例

      在Sizzle内部封装了一个方法,该方法负责将css选择器分解为一个数组。数组中的每一项是一个对象,格式如下:

        {

          "type" : "CLASS",

          "value" : ".red",
          "matchs" : " "

        }

      看一下tokenize的源码:

      // 假设传入进来的选择器是:div > p + .cl[type="checkbox"], #id:first-child
      // 这里可以分为两个规则:div > p + .aaron[type="checkbox"] 以及 #id:first-child
      // 返回的需要是一个Token序列
      // Sizzle的Token格式如下 :{value:'匹配到的字符串', type:'对应的Token类型', matches:'正则匹配到的一个结构'}
      function tokenize( selector, parseOnly ) {
        var matched, match, tokens, type,
        soFar, groups, preFilters,
        cached = tokenCache[ selector + " " ];
        // 这里的soFar是表示目前还未分析的字符串剩余部分
        // groups表示目前已经匹配到的规则组,在这个例子里边,groups的长度最后是2,存放的是每个规则对应的Token序列

        // 如果cache里边有,直接拿出来即可
        if ( cached ) {
          return parseOnly ? 0 : cached.slice( 0 );
        }

        // 初始化
        soFar = selector;

        // 这是最后要返回的结果,一个二维数组

        // 有多少个并联选择器,里面就有多少个数组,数组里面是拥有value与type的对象
        groups = []; 

        // 这里的预处理器为了对匹配到的Token适当做一些调整
        // 自行查看源码,其实就是正则匹配到的内容的一个预处理
        preFilters = Expr.preFilter;

        // 递归检测字符串
        // 比如"div > p + .cl input[type="checkbox"]"
        while ( soFar ) {

          //  以第一个逗号切割选择符,然后去掉前面的部分,处理同时传入多个同级选择器的情况,例如:$( "div, span" )
          if ( !matched || (match = rcomma.exec( soFar )) ) {
            if ( match ) {
              // 如果匹配到逗号,将soFar中匹配到的部分删除掉
              soFar = soFar.slice( match[0].length ) || soFar;
            }
            // 往规则组里边压入一个Token序列,目前Token序列还是空的
            groups.push( tokens = [] );
          }

          // 将matched重置为false,为下次判断soFar中是否有内容做准备

          matched = false;

          // 将刚才前面的部分以关系选择器再进行划分
          // 先处理这几个特殊的Token : >, +, 空格, ~
          // 因为他们比较简单,并且是单字符的
          if ( (match = rcombinators.exec( soFar )) ) {
            // 获取到匹配的字符
            matched = match.shift();
            // 放入Token序列中
            tokens.push({
              value: matched,
              type: match[0].replace( rtrim, " " )
            });
            // 剩余还未分析的字符串需要减去这段已经分析过的
            soFar = soFar.slice( matched.length );
          }

          // 这里开始分析这几种Token : TAG, ID, CLASS, ATTR, CHILD, PSEUDO, NAME
          // 将每个选择器组依次用ID,TAG,CLASS,ATTR,CHILD,PSEUDO这些正则进行匹配
          // Expr.filter里边对应地 就有这些key
          //如果通过正则匹配到了Token格式:match = matchExpr[ type ].exec( soFar )
          //然后看看需不需要预处理:!preFilters[ type ]
          //如果需要 ,那么通过预处理器将匹配到的处理一下 : match = preFilters[ type ]( match )

          for ( type in Expr.filter ) {

            if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
              (match = preFilters[ type ]( match ))) ) {
              matched = match.shift();
              //放入Token序列中
              tokens.push({
                value: matched,
                type: type,
                matches: match
            });
            //剩余还未分析的字符串需要减去这段已经分析过的
            soFar = soFar.slice( matched.length );
          }
        }

        //如果到了这里都还没matched到,那么说明这个选择器在这里有错误
        //直接中断词法分析过程
        //这就是Sizzle对词法分析的异常处理
        if ( !matched ) {
          break;
        }
      }
      //放到tokenCache函数里进行缓存
      //如果只需要这个接口检查选择器的合法性,直接就返回soFar的剩余长度,倘若是大于零,说明选择器不合法
      //其余情况,如果soFar长度大于零,抛出异常;否则把groups记录在cache里边并返回,
      return parseOnly ?
        soFar.length :
        soFar ?
        Sizzle.error( selector ) :
        tokenCache( selector, groups ).slice( 0 );
    }

  • 相关阅读:
    CVE-2019-16278:Nostromo Web服务器的远程命令执行
    内网渗透一(信息收集)
    Apache Flink 任意jar包上传漏洞
    Apache ---- Solrl漏洞复现
    linux内核过高导致vm打开出错修复脚本
    lvm拓展
    文件时间进度扫描控制,可回溯,空闲扫描,系统时间调整不影响
    Raid 管理
    curl 工具使用
    docker 入门
  • 原文地址:https://www.cnblogs.com/charling/p/3501118.html
Copyright © 2011-2022 走看看