jQuery选择器源码解读(三):tokenize方法

让我来详细讲解一下“jQuery选择器源码解读(三):tokenize方法”的完整攻略。

什么是tokenize方法?

在jQuery中,选择器是通过parseTree方法来解析的。而在parseTree方法中,会先调用tokenize方法来将选择器字符串转化为一组tokens,然后再将这些tokens组合成语法树。因此,tokenize方法是解析选择器字符串的第一步,也是非常重要的一步。

tokenize方法的定义和参数

tokenize方法定义在jQuery的内部方法中,其代码如下:

tokenize: function( selector, parseOnly ) {
    var matched, match, tokens, type, soFar, groups, preFilters,
        cached = tokenCache[ selector + " " ];

    if ( cached ) {
        return parseOnly ? 0 : cached.slice( 0 );
    }

    soFar = selector;
    groups = [];
    preFilters = Expr.preFilter;

    while ( soFar ) {

        // Comma and first run
        if ( !matched || (match = rcomma.exec( soFar )) ) {
            if ( match ) {
                // Don't consume trailing commas as valid
                soFar = soFar.slice( match[0].length ) || soFar;
            }
            groups.push( (tokens = []) );
        }

        matched = false;

        // Combinators
        if ( (match = rcombinators.exec( soFar )) ) {
            tokens.push( matched = new Token( match.shift() ) );
            soFar = soFar.slice( matched.length );

            // Cast descendant combinators to space
            matched.type = match[0].replace( rtrim, " " );
        }

        // Filters
        for ( type in Expr.filter ) {
            if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || (match = preFilters[ type ]( match ))) ) {
                tokens.push( matched = new Token( match.shift() ) );
                soFar = soFar.slice( matched.length );
                matched.type = type;
                matched.matches = match;
            }
        }

        if ( !matched ) {
            break;
        }
    }

    // Return the length of the invalid excess
    // if we're just parsing
    // Otherwise, throw an error or return tokens
    return parseOnly ?
        soFar.length :
        soFar ?
            Sizzle.error( selector ) :
            // Cache the tokens
            tokenCache( selector, groups ).slice( 0 );
}

可以看到,tokenize方法接受两个参数:

  • selector:即要解析的选择器字符串;
  • parseOnly:一个布尔值,如果为true,则只解析选择器字符串并返回其余字符串的长度,不返回匹配的token列表。否则解析并返回匹配的token列表。

tokenize方法的实现机理

tokenize方法的实现机理比较复杂,主要流程如下:

  1. 定义一些变量
var matched, match, tokens, type, soFar, groups, 
    preFilters, cached = tokenCache[ selector + " " ];
  • matched:记录当前是否匹配成功;
  • match:储存当前匹配到的结果;
  • tokens:存储当前组的tokens;
  • type:储存当前模拟器或过滤器的类型;
  • soFar:剩余的未匹配的字符串;
  • groups:存储所有的tokens;
  • preFilters:存储Expr.preFilter对象,即过滤器前置类;
  • cached:存储tokenCache中对应的缓存。

  • 根据缓存返回结果

if ( cached ) {
    return parseOnly ? 0 : cached.slice( 0 );
}

如果该选择器已经缓存过,直接返回token列表或者字符串的长度。

  1. 预处理
soFar = selector;
groups = [];
preFilters = Expr.preFilter;

将传递进来的selector字符串赋值给soFar,初始化groups和preFilters变量。preFilters变量的作用是保存过滤器前置类(Expr.preFilter)。

  1. 检查组(group)情况
if ( !matched || (match = rcomma.exec( soFar )) ) {
    if ( match ) {
        // Don't consume trailing commas as valid
        soFar = soFar.slice( match[0].length ) || soFar;
    }
    groups.push( (tokens = []) );
}

如果没有匹配到组或者匹配到了逗号,则开始一个新的组,将tokens数组置为空,同时将该组加入到groups中。

  1. 检查关系选择器
if ( (match = rcombinators.exec( soFar )) ) {
    tokens.push( matched = new Token( match.shift() ) );
    soFar = soFar.slice( matched.length );
    matched.type = match[0].replace( rtrim, " " );
}

如果当前soFar开头是一个关系选择器(类似于'>','+'等),则将该关系选择器记录下来,并将soFar的值置为除去该关系选择器后的字符串。同时,将matched类型改为关系选择器类型。

  1. 检查过滤器
for ( type in Expr.filter ) {
    if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || (match = preFilters[ type ]( match ))) ) {
        tokens.push( matched = new Token( match.shift() ) );
        soFar = soFar.slice( matched.length );
        matched.type = type;
        matched.matches = match;
    }
}

遍历Expr.filter对象,每个过滤器定义一个正则表达式。如果当前的soFar匹配到了某个过滤器的正则表达式,则将该过滤器记录下来,并更新soFar的值。同时,将matched类型改为该过滤器类型。

  1. 处理结束
if ( !matched ) {
    break;
}

如果一个token都没匹配到,则结束。

  1. 返回结果
return parseOnly ?
    soFar.length :
    soFar ?
        Sizzle.error( selector ) :
        // Cache the tokens
        tokenCache( selector, groups ).slice( 0 );

如果parseOnly参数为true,则只返回未匹配的字符串的长度;如果soFar不为空,则抛出异常。否则将匹配到的token列表缓存起来,并返回该列表的副本。

示例说明

下面给出两个示例说明tokenize方法的使用。

示例一

假设我们要解析的selector为:".foo .bar, div > span"

使用tokenize方法进行解析:

var tokens = Sizzle.tokenize( '.foo .bar, div > span' );
console.log( tokens );

输出结果:

[
  [ { type: 'CLASS', matches: [ 'foo' ] }, { type: 'DESCENDANT', matches: [] }, { type: 'CLASS', matches: [ 'bar' ] } ],
  [ { type: 'TAG', matches: [ 'div' ] }, { type: 'CHILD', matches: [] }, { type: 'TAG', matches: [ 'span' ] } ]
]

可以看到,结果正好符合预期,解析后的选择器,被正确地拆分成了两个组,每个组中存储着相应的tokens。

示例二

假设我们要解析的selector为:"div[attr1][attr2~=value]"

使用tokenize方法进行解析:

var tokens = Sizzle.tokenize( 'div[attr1][attr2~=value]' );
console.log( tokens );

输出结果:

[ 
  [ { type: 'TAG', matches: [ 'div' ] }, { type: 'ATTR', matches: [ 'attr1' ] }, { type: 'ATTR', matches: [ 'attr2', 'value', '~=' ] } ]
]

可以看到,结果正好符合预期,解析后的选择器中包含了tag和attr类型的tokens,同时也记录了属性名(match[1])和属性值(match[2])。

至此,我们完成了对"jQuery选择器源码解读(三):tokenize方法"的详细解释。希望对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:jQuery选择器源码解读(三):tokenize方法 - Python技术站

(0)
上一篇 2023年5月27日
下一篇 2023年5月27日

相关文章

  • jQuery Mobile面板 classes.pagePanel选项

    jQuery Mobile是一个面向移动设备的JavaScript框架,提供了大量的组件和工具来简化移动网站和应用程序的开发过程。其中,面板是一个非常有用的功能,可以为我们的移动应用提供便捷的导航和布局控制。而classes.pagePanel选项则可以帮我们针对面板进行样式自定义。 一、classes.pagePanel选项简介 在使用jQuery Mob…

    jquery 2023年5月12日
    00
  • jQWidgets jqxFormattedInput关闭事件

    jQWidgets jqxFormattedInput关闭事件 jQWidgets是一个基于jQuery的UI组件库,提供了丰富的UI组件和工具包括表格、日历下拉单等。jqxFormattedInput是jQWidgets的组件之一,用于创建格式化的输入框。close事件是jqFormattedInput`的一个事件,用于在输入框关闭时触发。 close事件…

    jquery 2023年5月9日
    00
  • AngularJS 中的指令实践开发指南(一)

    下面是对于“AngularJS 中的指令实践开发指南(一)”的完整攻略。 什么是指令 指令是 AngularJS 中一种重要的概念,它可以在 HTML 模板中添加自定义的 HTML 标签、属性、类名和注释等方式来扩展 HTML 的功能。指令可以用来实现很多有用的功能,比如自定义表单控件、动态引入模板、实现分页等。 定义指令 在 AngularJS 中,我们可…

    jquery 2023年5月27日
    00
  • jQWidgets jqxKnob spinner属性

    jQWidgets jqxKnob spinner属性攻略 jQWidgets 是一个基于 jQuery 的 UI 组件库,提供了丰富的 UI 组件和工具,可于创建现代化用程序。 jqxKnob 旋钮,于可视化调整数值。本攻略将详细介绍 jqxKnob 的spinner属性,包括spinner` 的使用方法和示例。 spinner 属性 jqxKnob 组件…

    jquery 2023年5月10日
    00
  • 基于cookie实现zTree树刷新后展开状态不变

    要实现基于cookie的zTree树刷新后展开状态不变,可以按照以下步骤操作: 1. 引入cookie插件 首先,在页面中引入cookie插件,例如jquery.cookie.js: <script src="https://cdn.bootcdn.net/ajax/libs/jquery-cookie/1.4.1/jquery.cookie…

    jquery 2023年5月28日
    00
  • jQWidgets jqxGrid pagerheight属性

    jQWidgets 是一个流行的 JavaScript UI 库,提供了许多可定制的 UI 组件。其中一个组件是 jqxGrid,它是一个用于创建网格的控件。jqxGrid 组件提供多个属性,其中之一是 pagerheight 属性。下面是关于 jqxGrid 的 pagerheight 属性的详细攻略: pagerheight 属性概述 pagerheig…

    jquery 2023年5月11日
    00
  • jQuery实现高亮显示的方法

    jQuery是一种流行的JavaScript库,它可以帮助我们更方便地操作DOM元素。在网页开发中,常常需要对某些内容进行高亮显示,下面就来详细讲解“jQuery实现高亮显示的方法”的完整攻略。 步骤一:引入jQuery库 在使用jQuery之前,我们需要先引入jQuery库。可以在页面的<head>标签中添加以下代码: <script s…

    jquery 2023年5月28日
    00
  • jQuery UI菜单focus事件

    下面是完整的“jQuery UI菜单focus事件”的讲解攻略: jQuery UI菜单focus事件 什么是jQuery UI菜单? jQuery UI是基于jQuery的一套用户界面组件库。其中的菜单组件(Menu)提供了一种方便快捷的方式来创建菜单,并支持键盘导航、自定义样式、事件等功能。 菜单可以是横向或纵向,并且可以包含多个级别的子菜单。除了用鼠标…

    jquery 2023年5月12日
    00
合作推广
合作推广
分享本页
返回顶部