zoukankan      html  css  js  c++  java
  • jQuery.API源码深入剖析以及应用实现(1) - 核心函数篇

    前言

    Jquery(http://jquery.com/)是一个轻量级,快速简洁的Javascript框架,它的容量小巧,简洁和简短的语法,容易记;用户能更方便地处理HTML DOMEvents、实现动画效果,并且提供Ajax的支持。目前最新版本为 jQuery 1.3.1(http://jqueryjs.googlecode.com/files/jquery-1.3.1.js),这系列文章将对该版本的源码进行阐述。

    现在开始本系列的第一篇,Jquery核心函数,内容主要包括:

     

    分析

    1. 在Jquery的应用开发中,我们经常看到这样的代码:

    $("div .container").css("display","none"); //将div节点下样式值为container的节点设置为不显示
    var width = $("div .container").width(); //得到div节点下样式值为container的宽度
    var html = $(document.getElementById("result")).html(); //得到id为result的节点的innerHTML值
    $("#result", document.forms[0]).css("color""red"); //将在第一个Form节点下id为result的字体颜色设置为红色
    $("<div>hello,world</div>").appendTo("#result"); //将HTML字符串信息 内部追加到 id为result的节点末尾

    那么$(...)里面的参数,Jquery API中是怎样辨认参数是表达式,id,HTML字符串,还是DOM元素呢?

    现在我们来深入剖析Jquery源码。


    2. 这里,我先来做个测试,我将Jquery API简化为这样的代码:

    (function(){
        
    var window = this,
        
        jQuery 
    = window.jQuery = window.$ = function(selector, context){
            
    return new jQuery.fn.init(selector, context);
        };
        
        jQuery.fn 
    = jQuery.prototype = {
            init : 
    function(selector, context) {
                alert(selector); 
    //弹出警告框
            }
        };
    })();
    window.onload 
    = function() {
        $(
    "div .container"); //得到“div . container”
        $("#result"); //得到“#result”
        $("<div>hello,world</div>"); //得到“<div>hello,world</div>”
        $(document.getElementById("result")); //得到“[object]”
    }

    从这里我们可以得出,实际上$里面的参数(表达式字符串,ID字符串,HTML字符串,DOM对象),主要就是在init方法中各自实现它们自己的逻辑

    现在列出init方法的具体实现:

        initfunction( selector, context ) {
            
    // Make sure that a selection was provided
            selector = selector || document;

            
    // Handle $(DOMElement)
            if ( selector.nodeType ) {
                
    this[0= selector;
                
    this.length = 1;
                
    this.context = selector;
                
    return this;
            }
            
    // Handle HTML strings
            if ( typeof selector === "string" ) {
                
    // Are we dealing with HTML string or an ID?
                var match = quickExpr.exec( selector );

                
    // Verify a match, and that no context was specified for #id
                if ( match && (match[1|| !context) ) {

                    
    // HANDLE: $(html) -> $(array)
                    if ( match[1] )
                        selector 
    = jQuery.clean( [ match[1] ], context );

                    
    // HANDLE: $("#id")
                    else {
                        
    var elem = document.getElementById( match[3] );

                        
    // Handle the case where IE and Opera return items
                        // by name instead of ID
                        if ( elem && elem.id != match[3] )
                            
    return jQuery().find( selector );

                        
    // Otherwise, we inject the element directly into the jQuery object
                        var ret = jQuery( elem || [] );
                        ret.context 
    = document;
                        ret.selector 
    = selector;
                        
    return ret;
                    }

                
    // HANDLE: $(expr, [context])
                // (which is just equivalent to: $(content).find(expr)
                } else
                    
    return jQuery( context ).find( selector );

            
    // HANDLE: $(function)
            // Shortcut for document ready
            } else if ( jQuery.isFunction( selector ) )
                
    return jQuery( document ).ready( selector );

            
    // Make sure that old selector state is passed along
            if ( selector.selector && selector.context ) {
                
    this.selector = selector.selector;
                
    this.context = selector.context;
            }

            
    return this.setArray(jQuery.makeArray(selector));
        }

     

    3. 现在分析 表达式,id,HTML字符串,DOM元素等等各自的实现:

    1)形如 $(document.getElementById("result")) 【jQuery(elements)】DOM元素的实现,通过init方法中的以下代码:

     // Handle $(DOMElement)
      if ( selector.nodeType ) {
       
    this[0= selector;
       
    this.length = 1;
       
    this.context = selector;
       
    return this;
      }

    selector.nodeType判断当selector为元素节点时,将length置为1,并且赋值于context,实际上context作为init的第二个参数,它意味着它的上下文节点就是selector该点,返回它的$(...)对象。

    2)形如 $("<div>hello,world</div>") 【jQuery(html,[ownerDocument])】HTML字符串的实现,通过init方法中的以下代码:

    // 判断selector为字符串
    if ( typeof selector === "string" ) {
        
    // quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/
        // 利用检查正则表达式HTML字符串还是元素ID字符串
        var match = quickExpr.exec( selector );
        
        
    if ( match && (match[1|| !context) ) {

            
    // 处理HTML字符串
            if ( match[1] )
                selector 
    = jQuery.clean( [ match[1] ], context );

            
    // 处理形如$("#id")
            else {
                
    // 
            }
        
        } 
        
    // 处理 形如 $("div .container")的表达式字符串
        else
            
    // 

    }
     
    // 处理 形如 $(function) , $(document).ready(function(){})的表示
    else if ( jQuery.isFunction( selector ) ) {

    }
    // 

    关键看到这样的一句代码,selector = jQuery.clean( [ match[1] ], context ); 继续查看clean都做了些什么:

    Code

    这么长的一串代码 实际上最后访问的是一个ret为变量的数组,而数组中的元素变为以DOM元素的对象,而它的innerHTML正好就是刚才的HTML字符串。


    3)形如 $("#result") 【jQuery(expression,[context])】ID字符串的实现,通过init方法中的以下代码:

    // 处理形如$("#result")
    else {
        
    // match[3]得到ID的值如:result
        var elem = document.getElementById( match[3] );

        
    if ( elem && elem.id != match[3] )
            
    return jQuery().find( selector );

        
    // 调用jQuery(elements)方式
        var ret = jQuery( elem || [] );
        
    // 默认上下文DOM为window.document
        ret.context = document;
        ret.selector 
    = selector;
        
    return ret;
    }

    根据match[3]可以得到DOM对象elem,并且调用2)介绍的jQuery(elements),最后返回一个ret为变量的jquery对象。


    4)形如 $("div .container") 【jQuery(expression,[context])】表达式字符串的实现,通过init方法中的以下代码:

    // 处理 形如 $("div .container")的表达式字符串
    else
      
    return jQuery( context ).find( selector );

    关键看到这样的一句代码,jQuery().find( selector ); 继续查看find都做了些什么:

    find: function( selector ) {
        
    // 当表达式不包含“,”符号时候
        if ( this.length === 1 && !/,/.test(selector) ) {
            
    var ret = this.pushStack( [], "find", selector );
            ret.length 
    = 0;
            jQuery.find( selector, 
    this[0], ret );
            
    return ret;
        } 
        
    // 当表达式包含“,”符号时候
        else {
            
    var elems = jQuery.map(thisfunction(elem){
                
    return jQuery.find( selector, elem );
            });

            
    return this.pushStack( /[^+>] [^+>]/.test( selector ) ?
                jQuery.unique( elems ) :
                elems, 
    "find", selector );
        }
    }

    先看下表达式不包含“,”符号的时候,调用pushStack方法,方法为:

    // 将一系列元素推入栈中
    pushStack: function( elems, name, selector ) {

        
    var ret = jQuery( elems );

        
    // 将上个对象的引用推入栈中
        ret.prevObject = this;

        ret.context 
    = this.context;

        
    // 关键字为find时,在原有selector的基础上,继续增加selector
        // 如 $("div").find("p") 意思就是 $("div p")
        if ( name === "find" )
            ret.selector 
    = this.selector + (this.selector ? " " : ""+ selector;
        
    else if ( name )
            ret.selector 
    = this.selector + "." + name + "(" + selector + ")";

        
    // 返回最新的Jquery对象
        return ret;
    }

    注意这里看到 ret.prevObject = this;  这个方法在$(...).andSelf()$(...).end()中调用,对于筛选或查找后的元素,返回前一次元素状态它是很有用的。

    接着调用 jQuery.find( selector, this[0], ret ); ,首先我们看到有这样的几句代码:

    jQuery.find = Sizzle;
    jQuery.filter 
    = Sizzle.filter;
    jQuery.expr 
    = Sizzle.selectors;
    jQuery.expr[
    ":"= jQuery.expr.filters;
    // 
    window.Sizzle = Sizzle;

    jQuery.find方法转去调用全局的Sizzle对象了(实际上这里运用到了Javascript设计模式中的适配器模式,jquery.find实际上调用的是Sizzle的对象。关于Javascript适配器模式,我将接下来的Javascript乱弹设计模式系列文章中具体叙述),Sizzle对象定义为:

    Code

    呵呵,好长的一段代码,实际最关键的一句代码:Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
    对表达式字符串进行解析,最后返回一个jQuery对象,它就是 表达式字符串 最后想要的jQuery对象。


    当表达式包含“,”符号的时候,查看这样的一句代码:return this.pushStack( /[^+>] [^+>]/.test( selector ) ? jQuery.unique( elems ) : elems, "find", selector );

    它的意思是当表达式字符串包含“+”,“>”作为选择器(比如$("form > input") 或者 $("label + input") )的时候,将作为jQuery.map返回值的elems数组删除重复的元素,这个是有必要的。
    最后也是返回一个jQuery对象,它就是 表达式字符串 最后想要的jQuery对象。


    5)最后一点,形如 $(function) , $(document).ready(function(){})的表示,通过init方法中的以下代码来实现:

    // 处理 形如 $(function) , $(document).ready(function(){})的表示
    else if ( jQuery.isFunction( selector ) )
        
    return jQuery( document ).ready( selector );

    如果判断selector是函数的话,将执行jQuery(document).ready(selector);
    ready方法具体为:

    ready: function(fn) {
        
    // 绑定事件监听
        bindReady();

        
    if ( jQuery.isReady )
            fn.call( document, jQuery );

        
    else
            jQuery.readyList.push( fn );

        
    return this;
    }

    bindReady方法将事件绑定在文档加载完毕之后,最后通过调用fn.call( document, jQuery );来激发事件的执行。

     

    好了,jQuery的核心函数的原理机制就是这样的,下一篇我将谈下jQuery对象访问和数据缓存的原理机制

  • 相关阅读:
    win7网络共享原来如此简单,WiFi共享精灵开启半天都弱爆了!
    JQUERY UI Datepicker Demo
    Official online document, install svn server in centOS
    JAVE not work in linux
    AMR 转mp3 失败
    XD, XR, DR 股票
    Linux 下MySql 重置密码
    Difinition Of Done
    Apache, Tomcat, JK Configuration Example
    Linux 安装tomcat
  • 原文地址:https://www.cnblogs.com/lzhdim/p/1390612.html
Copyright © 2011-2022 走看看