jQuery源码研究:选择器

jQuery的css选择器,是一大亮点,其实现源码也可单独拎出来作为模块使用。

先看个整体,在jQuery源码中在行229-2752区域。

var Sizzle = (function(window){
    // 具体实现暂略...
})(window)

css选择器的具体实现是一个匿名自执行函数,传入参数为window对象。函数顶部定义若干变量,包括本地文档变量、特定实例数据和特定实例方法,此外还定义了一些为选择器字符串服务的正则表达式。数量太多就不一一列举了,感兴趣的可以自己去看源码吧。

方法的主体从行715开始直到结束,定义了Sizzle构造函数,若干工具方法和Sizeele静态方法及属性,概览看下图,由于内容太多,只截部分:

1、Sizzle构造函数:

function Sizzle( selector, context, results, seed ){
    var m, i, elem, nid, match, groups, newSelector,
        newContext = context && context.ownerDocument,
        //上下文默认为document,节点类型默认为9
        nodeType = context ? context.nodeType : 9;
    results = results || [];

    // 对选择器值为非字符串、为假、节点类型不符合要求时的返回值进行处理
    if ( typeof selector !== "string" || !selector ||
        nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {

        return results;
    }

    // 操作HTML文档
    if ( !seed ) {

        if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
            setDocument( context );
        }
        context = context || document;

        if ( documentIsHTML ) {

            if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {

                // ID 选择器
                if ( (m = match[1]) ) {

                    // 文档内容
                    if ( nodeType === 9 ) {
                        if ( (elem = context.getElementById( m )) ) {

                            if ( elem.id === m ) {
                                results.push( elem );
                                return results;
                            }
                        } else {
                            return results;
                        }

                    // 元素内容 
                    } else {

                        if ( newContext && (elem = newContext.getElementById( m )) &&
                            contains( context, elem ) &&
                            elem.id === m ) {

                            results.push( elem );
                            return results;
                        }
                    }

                // 类型选择器
                } else if ( match[2] ) {
                    push.apply( results, context.getElementsByTagName( selector ) );
                    return results;

                // Class 选择器
                } else if ( (m = match[3]) && support.getElementsByClassName &&
                    context.getElementsByClassName ) {

                    push.apply( results, context.getElementsByClassName( m ) );
                    return results;
                }
            }

            if ( support.qsa &&
                !compilerCache[ selector + " " ] &&
                (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {

                if ( nodeType !== 1 ) {
                    newContext = context;
                    newSelector = selector;

                } else if ( context.nodeName.toLowerCase() !== "object" ) {

                    if ( (nid = context.getAttribute( "id" )) ) {
                        nid = nid.replace( rcssescape, fcssescape );
                    } else {
                        context.setAttribute( "id", (nid = expando) );
                    }

                    groups = tokenize( selector );
                    i = groups.length;
                    while ( i-- ) {
                        groups[i] = "#" + nid + " " + toSelector( groups[i] );
                    }
                    newSelector = groups.join( "," );

                    newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
                        context;
                }

                if ( newSelector ) {
                    try {
                        push.apply( results,
                            newContext.querySelectorAll( newSelector )
                        );
                        return results;
                    } catch ( qsaError ) {
                    } finally {
                        if ( nid === expando ) {
                            context.removeAttribute( "id" );
                        }
                    }
                }
            }
        }
    }

    // 返回 调用select()方法后的值
    return select( selector.replace( rtrim, "$1" ), context, results, seed );
}

Sizzle函数是整个css选择器的入口函数。

本文分享自微信公众号 - 前端小二(frontendxiao2)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-12-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Tech爬虫(公众号php_pachong)

HTML是什么?

html就是要告诉浏览器我的某个东西是什么,没错,这就是它的主要功能。html的实质,他就是一种标签,一种人和浏览器交流的标签,我们只有告诉浏览器这是什么,他才...

16930
来自专栏我的前端路

web 深入视角:变态的静态资源缓存与更新

这是一个非常有趣的 非主流前端领域,这个领域要探索的是如何用工程手段解决前端开发和部署优化的综合问题,入行到现在一直在学习和实践中。 在我的印象中,facebo...

10400
来自专栏Tech爬虫(公众号php_pachong)

css优先级

多重样式(MultipleStyles):如果外部样式、内部样式和内联样式同时应用于同一个元素,就是使多重样式的情况。

8030
来自专栏前端达人

「CSS 3D 专题」搞懂 CSS 3D,你必须理解 perspective(视域)这个属性

上一章节《学习前,你需要了解什么是CSS 3D?》里,我们一起了解什么是CSS 3D,本篇章节笔者将带着大家学习 perspective(视域)这个重要属性,在...

10720
来自专栏sktj

flask 模板获取静态文件(flask 17)

{% macro static_file(type, filename_or_url, local=True) %} {% if local -%} {% ...

11010
来自专栏Tech爬虫(公众号php_pachong)

PHP是什么

学习一样技能,你得先清楚这项技能是到底做什么的,说到这里,我想大家都会简单的说是做网站的,因为PHP在WEB领域应用最为广泛,大多数网站都是用PHP做的。准确的...

10330
来自专栏从零开始学 Web 前端

css实现内容不相同的左右两个div等高

现在有两个div左右排列,但是两个div的内容不相同,如何设置两个div的css做到在两个div等高排列呢?

6720
来自专栏前端导学

使用APP_INITIALIZER实现Angular运行时环境变量配置

你可以通过在app.compontent.ts中添加console.log来判断一下是否appConfig早于app.component执行

12620
来自专栏Tech爬虫(公众号php_pachong)

利用Div + CSS快速布局页面

所谓Div + CSS,是指通过HTML「层」标签——<div></div>,辅以CSS中对该「层」宽度、排列等样式的定义,来实现网页布局的一种方式

19810
来自专栏Tech爬虫(公众号php_pachong)

如何把设计稿还原成真实网页

所谓的前端是指什么呢?前端(front-end)是相对后端(back-end)而言的

9320

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励