jquery core 源码分析

  1. **  
  2.  * author:prk  
  3.  * date:2008-08-05  
  4.  * comment:analeyse the core of jquery1.2.6  
  5.  *     
  6.  */  
  7.   
  8. /*  
  9.  * jQuery  
  10.  *   
  11.  * @VERSION - New Wave Javascript  
  12.  *   
  13.  * Copyright (c) 2008 John Resig (jquery.com) Dual licensed under the MIT  
  14.  * (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.  
  15.  *   
  16.  * $Date: 2008-07-24 01:00:32 +0800 (Thu, 24 Jul 2008) $ $Rev: 5793 $  
  17.  */  
  18.   
  19. // Map over jQuery in case of overwrite   
  20. var _jQuery = window.jQuery,   
  21. // Map over the $ in case of overwriteff   
  22. _$ = window.$;   
  23.   
  24. var jQuery = window.jQuery = window.$ = function(selector, context) {   
  25.     // The jQuery object is actually just the init constructor 'enhanced'   
  26.     return new jQuery.fn.init(selector, context);   
  27. };   
  28.   
  29. // A simple way to check for HTML strings or ID strings   
  30. // (both of which we optimize for)   
  31. var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,   
  32.   
  33. // Is it a simple selector   
  34. isSimple = /^.[^:#\[\.]*$/,   
  35.   
  36. // Will speed up references to undefined, and allows munging its name.   
  37. undefined;   
  38.   
  39. jQuery.fn = jQuery.prototype = {   
  40.     init : function(selector, context) {   
  41.         selector = selector || document;// 确定selector存在   
  42.   
  43.         // 第一种情况 Handle $(DOMElement)单个Dom 元素,忽略上下文   
  44.         if (selector.nodeType) {   
  45.             this[0] = selector;   
  46.             this.length = 1;   
  47.             return this;   
  48.         }          
  49.         if (typeof selector == "string") {//selector为string   
  50.             // Are we dealing with HTML string or an ID?   
  51.             var match = quickExpr.exec(selector);   
  52.             // Verify a match, and that no context was specified for #id   
  53.             if (match && (match[1] || !context)) {   
  54.                 if (match[1])// 第二种情况处理$(html) -> $(array)   
  55.                     selector = jQuery.clean([match[1]], context);   
  56.                 else {// 第三种情况:HANDLE: $("#id")//处理$("#id")   
  57.                     var elem = document.getElementById(match[3]);   
  58.   
  59.                     // Make sure an element was located   
  60.                     if (elem) {   
  61.                         // Handle the case where IE and Opera return items   
  62.                         // by name instead of ID   
  63.                         if (elem.id != match[3])   
  64.                             return jQuery().find(selector);// 默认是document.find()   
  65.   
  66.                         // Otherwise, we inject the element directly into the   
  67.                         // jQuery object   
  68.                         return jQuery(elem);   
  69.                     }   
  70.                     selector = [];   
  71.                 }   
  72.             } else  
  73.                 // 第四种情况:处理$(expr, [context])==$(content).find(expr)   
  74.                 return jQuery(context).find(selector);   
  75.         } else if (jQuery.isFunction(selector))   
  76.             // 第五种情况:处理$(function)七Shortcut for document ready   
  77.             return jQuery(document)[jQuery.fn.ready ? "ready" : "load"](selector);   
  78.   
  79.         // 第六种情况:处理$(elements)   
  80.         return this.setArray(jQuery.makeArray(selector));   
  81.     },   
  82.   
  83.     // 当前的版本号   
  84.     jquery : "@VERSION",   
  85.   
  86.     // jquery对象中的元素的个数。jquery像数组。能通过$('p')[0]去取得Dom对象。   
  87.     size : function() {   
  88.         return this.length;   
  89.     },   
  90.     // jquery对象的元素的个数   
  91.     length : 0,   
  92.   
  93.     // 取到本jquery对象的第几个Dom元素,无参数,代表全部的Dom元素   
  94.     get : function(num) {   
  95.         return num == undefined ? jQuery.makeArray(this) : this[num];   
  96.     },   
  97.   
  98.     // 采用jQuery构建新对象,同时引用老对象。   
  99.     pushStack : function(elems) {   
  100.         var ret = jQuery(elems);// 构建新的jquery对象   
  101.         ret.prevObject = this;// 保存老的对象的引用   
  102.         return ret;   
  103.     },   
  104.   
  105.     // 把array-like对象的元素全部push当前jquery对象。   
  106.     setArray : function(elems) {   
  107.         this.length = 0;   
  108.         Array.prototype.push.apply(this, elems);   
  109.         return this;   
  110.     },   
  111.   
  112.     // 当前jquery对象中每个元素都执行callback(index,elem)函数   
  113.     each : function(callback, args) {// 返回this   
  114.         // 其调用了jQuery的静态方法。prototype中的mothodize是解决这类问题的好方法   
  115.         return jQuery.each(this, callback, args);   
  116.     },   
  117.   
  118.     // 找到elem在本jquery对象的位置(index)   
  119.     index : function(elem) {   
  120.         var ret = -1;   
  121.         return jQuery.inArray( // 如是jQuery对象就取第一个元素   
  122.                 elem && elem.jquery ? elem[0] : elem, this);   
  123.     },   
  124.   
  125.     // attr(properties)   
  126.     // 将“名/值”形式的对象设置为所有匹配元素的属性。   
  127.     // attr(name)   
  128.     // 取得第一个匹配元素的属性值。通过这个方法可以方便地从第一个匹配元素中获取一个属性的值。如果元素没有相应属性,则返回 undefined 。   
  129.     // attr(key,value)   
  130.     // 为所有匹配的元素设置一个属性值。$("img").attr("src","test.jpg");   
  131.     // attr(key,fn)   
  132.     // 为所有匹配的元素设置一个由这个函数计算的值做属性值。   
  133.     attr : function(name, value, type) {   
  134.         var options = name;// 支持"名/值"形式的对象和string   
  135.         if (name.constructor == String)   
  136.             if (value === undefined)   
  137.                 // 调用curCss,attr静态方法返回本对象第一个元素的name的属性值   
  138.                 return this[0] && jQuery[type || "attr"](this[0], name);   
  139.             else {// 设定属性值,把name String 转换成"名/值"对象,便于统一的处理   
  140.                 options = {};   
  141.                 options[name] = value;   
  142.             }   
  143.         return this.each(function(i) {// 为每个元素的指定的name属性设值   
  144.                     for (name in options)   
  145.                         // value=options[name],可以是Fn(index),this-->each elem   
  146.                         jQuery.attr(type ? this.style : this, name, jQuery   
  147.                                 .prop(this, options[name], type, i, name));   
  148.                 });   
  149.     },   
  150.   
  151.     // css(name)   
  152.     // 访问第一个匹配元素的样式属性。   
  153.     // css(name,value)   
  154.     // 在所有匹配的元素中,设置一个样式属性的值。数字将自动转化为像素值   
  155.     // css(properties)   
  156.     // 把一个“名/值对”对象设置为所有匹配元素的样式属性。这是一种在所有匹配的元素上设置大量样式属性的最佳方式。   
  157.     css : function(key, value) {   
  158.   
  159.         if ((key == 'width' || key == 'height') && parseFloat(value) < 0)   
  160.             value = undefined;// 忽略负数   
  161.         return this.attr(key, value, "curCSS");// 调用了curCSS方法   
  162.     },   
  163.   
  164.     // text()   
  165.     // 取得所有匹配元素的内容。结果是由所有匹配元素包含的文本内容组合起来的文本。这个方法对HTML和XML文档都有效。   
  166.     // text(val)   
  167.     // 设置所有匹配元素的文本内容.与 html() 类似, 但将编码 HTML (将 "<" 和 ">" 替换成相应的HTML实体).   
  168.     text : function(text) {   
  169.         if (typeof text != "object" && text != null)   
  170.             return this.empty()// 除去所有的子元素,加上创建的文本节点   
  171.                     .append((this[0] && this[0].ownerDocument || document)   
  172.                             .createTextNode(text));   
  173.   
  174.         var ret = "";   
  175.         jQuery.each(text || this, function() {// 所有匹配元素包含的文本内容组合起来   
  176.                     jQuery.each(this.childNodes, function() {   
  177.                         if (this.nodeType != 8)// 8:注释   
  178.                                 ret += (this.nodeType != 1// 元素的话,递归子元素   
  179.                                         ? this.nodeValue   
  180.                                         : jQuery.fn.text([this]));   
  181.                         });   
  182.                 });   
  183.   
  184.         return ret;   
  185.     },   
  186.   
  187.     // *****************************************************************************   
  188.     // 一组用于元素标签包裹操作的函数   
  189.   
  190.     // 将所有匹配的元素用单个元素包裹起来   
  191.     // 这个函数的原理是检查提供的第一个元素并在它的代码结构中找到最上层的祖先元素--这个祖先元素就是包装元素。   
  192.     // 这于 '.wrap()' 是不同的,'.wrap()'为每一个匹配的元素都包裹一次。   
  193.     wrapAll : function(html) {   
  194.         if (this[0])   
  195.             /*  
  196.              * 

    Hello

    cruel

    World

    。--> 
     
  197.              * $("p").wrapAll("
    ");-->调用wrapAll的jQuery对象,称:A。有三个元素。 
     
  198.              * 第一步:复制生成一个jQuery对象,称:B。得到:
    的元素。 
     
  199.              * 第二步:把B所有的元素都插在A[0]元素之前,得到

    Hello

    cruel

    World

     
     
  200.              * 第三步:找到B对象中所有元素的最内面的节点,如
     
    。称:inner Node; 
     
  201.              * 第四步:向所有innerNode内部插入A对象的所有元素,得到

    Hello

    cruel

    World

     
     
  202.              */  
  203.             jQuery(html, this[0].ownerDocument).clone().insertBefore(this[0])   
  204.                     .map(function() {// 找到当前元素的最下层的子节点   
  205.                         var elem = this;   
  206.                         while (elem.firstChild)   
  207.                             elem = elem.firstChild;   
  208.                         return elem;   
  209.                     }).append(this);// this指是调用wrapAll的jQuery对象。   
  210.   
  211.         return this;   
  212.     },   
  213.   
  214.     // 将每一个匹配的元素的子内容(包括文本节点)用一个HTML结构包裹起来   
  215.     wrapInner : function(html) {   
  216.         return this.each(function() {// 这里包裹的对象是每个元素的对象的contents()   
  217.                     jQuery(this).contents().wrapAll(html);   
  218.                 });   
  219.     },   
  220.   
  221.     // 对于当前的jquery对象的每个元素都执行wrapAll(html)   
  222.     wrap : function(html) {   
  223.         return this.each(function() {// 这里包裹的对象是每个元素的对象   
  224.                     jQuery(this).wrapAll(html);   
  225.                 });   
  226.     },   
  227.   
  228.     // ************************************************************************   
  229.   
  230.     // ******************************************************************   
  231.     // 该组方法主要是完成把元素插到什么地方,与Ext的DomHelp的功能相似。   
  232.     // 在一个元素之前,之后,元素的开始,结束位置   
  233.   
  234.     // 向每个匹配的元素内部追加内容。   
  235.     // 这个操作与对指定的元素执行appendChild方法,将它们添加到文档中的情况类似   
  236.     append : function() {   
  237.         return this.domManip(arguments, truefalse, function(elem) {   
  238.             if (this.nodeType == 1)   
  239.                 this.appendChild(elem);   
  240.         });   
  241.     },   
  242.     // 向每个匹配的元素内部前置内容。   
  243.     // 这是向所有匹配元素内部的开始处插入内容的最佳方式。   
  244.     prepend : function() {// elem =arguments的转化集合中的dom元素   
  245.         return this.domManip(arguments, truetrue, function(elem) {   
  246.             if (this.nodeType == 1)// this=jQuery对象的每个元素(对于tr之类会修正)   
  247.                     this.insertBefore(elem, this.firstChild);   
  248.             });   
  249.     },   
  250.   
  251.     // 在每个匹配的元素之前插入内容。   
  252.     before : function() {   
  253.         return this.domManip(arguments, falsefalse, function(elem) {   
  254.             this.parentNode.insertBefore(elem, this);// this=jQuery对象的每个元素   
  255.             });   
  256.     },   
  257.   
  258.     // 在每个匹配的元素之后插入内容   
  259.     after : function() {   
  260.         return this.domManip(arguments, falsetrue, function(elem) {   
  261.             this.parentNode.insertBefore(elem, this.nextSibling);   
  262.         });   
  263.     },   
  264.   
  265.     // ******************************************************************   
  266.   
  267.     // 回到最近的一个"破坏性"操作之前。即,将匹配的元素列表变为前一次的状态。   
  268.     end : function() {   
  269.         return this.prevObject || jQuery([]);   
  270.     },   
  271.   
  272.     // 搜索所有与指定表达式匹配的元素。这个函数是找出正在处理的元素的后代元素的好方法。   
  273.     // 所有搜索都依靠jQuery表达式来完成。这个表达式可以使用CSS1-3的选择器语法来写。   
  274.     find : function(selector) {   
  275.         var elems = jQuery.map(this, function(elem) {// 找到每个元素的满足的   
  276.                     return jQuery.find(selector, elem);   
  277.                 });   
  278.   
  279.         return this.pushStack(/[^+>] [^+>]/.test(selector) ? jQuery   
  280.                 .unique(elems) : elems);// 是不是返回不重复的元素?   
  281.     },   
  282.   
  283.     // clone当前对象,events表明是否clone事件   
  284.     clone : function(events) {   
  285.         // 对每个元素都进行加工(copy)后的集合重新构建jQuery对象   
  286.         var ret = this.map(function() {   
  287.             if (jQuery.browser.msie && !jQuery.isXMLDoc(this)) {   
  288.                 // IE 中cloneNode不能copy 通过attachEvent增加的事件   
  289.                 // 而innserHTML不能copy一些修改过的属性(仅作为属性储存)如input 的name   
  290.                 var clone = this.cloneNode(true), container = document   
  291.                         .createElement("div");   
  292.                 container.appendChild(clone);   
  293.                 return jQuery.clean([container.innerHTML])[0];   
  294.             } else  
  295.                 return this.cloneNode(true);   
  296.         });   
  297.   
  298.         // Need to set the expando to null on the cloned set if it exists   
  299.         // removeData doesn't work here, IE removes it from the original as well   
  300.         // this is primarily for IE but the data expando shouldn't be copied   
  301.         // over in any browser   
  302.         var clone = ret.find("*").andSelf().each(function() {   
  303.             if (this[expando] != undefined)   
  304.                 this[expando] = null;   
  305.         });   
  306.   
  307.         if (events === true)// clone所有事件   
  308.             this.find("*").andSelf().each(function(i) {   
  309.                 if (this.nodeType == 3)   
  310.                     return;   
  311.                 var events = jQuery.data(this"events");   
  312.   
  313.                 for (var type in events)   
  314.                     for (var handler in events[type])   
  315.                         jQuery.event.add(clone[i], type, events[type][handler],   
  316.                                 events[type][handler].data);   
  317.             });   
  318.   
  319.         return ret;   
  320.     },   
  321.   
  322.     // 筛选出与指定表达式匹配的元素集合。可以通过函数来筛选当前jQuery对象的   
  323.     // 元素,还有通过用逗号分隔多个表达式来筛选   
  324.     filter : function(selector) {// grep,multiFilter的综合   
  325.         return this.pushStack(jQuery.isFunction(selector)   
  326.                 && jQuery.grep(this, function(elem, i) {   
  327.                     return selector.call(elem, i);   
  328.                 }) || jQuery.multiFilter(selector, this));   
  329.     },   
  330.   
  331.     // 删除与指定表达式匹配的元素   
  332.     not : function(selector) {   
  333.         if (selector.constructor == String)// 采用jQuery表达式   
  334.             if (isSimple.test(selector))   
  335.                 return this.pushStack(jQuery.multiFilter(selector, thistrue));   
  336.             else  
  337.                 // 多表达式要过滤   
  338.                 selector = jQuery.multiFilter(selector, this);   
  339.   
  340.         var isArrayLike = selector.length// array-like的集合?   
  341.                 && selector[selector.length - 1] !== undefined   
  342.                 && !selector.nodeType;   
  343.         return this.filter(function() {// 过滤掉return false的元素   
  344.                     return isArrayLike ? jQuery.inArray(this, selector) < 0// this在selector中?   
  345.                             : this != selector;   
  346.                 });   
  347.     },   
  348.   
  349.     // 把与表达式匹配的元素添加到jQuery对象中。array(-like)的集合也可以追加进来   
  350.     add : function(selector) {   
  351.         return this.pushStack(jQuery.unique(jQuery.merge(this.get(),   
  352.                 typeof selector == 'string' ? jQuery(selector) : jQuery   
  353.                         .makeArray(selector))));   
  354.     },   
  355.   
  356.     // 用一个表达式来检查当前选择的元素集合,如果其中至少有一个元素符合这个给定的表达式就返回true。   
  357.     is : function(selector) {   
  358.         return !!selector && jQuery.multiFilter(selector, this).length > 0;   
  359.     },   
  360.   
  361.     // 检查当前的元素是否含有某个特定的类,如果有,则返回true   
  362.     hasClass : function(selector) {   
  363.         return this.is("." + selector);   
  364.     },   
  365.   
  366.     // 获得第一个匹配元素的当前值。   
  367.     // 在 jQuery 1.2 中,可以返回任意元素的值了。包括select。如果多选,将返回一个数组,其包含所选的值。   
  368.     // 设置每一个匹配元素的值。在 jQuery 1.2, 这也可以为select元件赋值   
  369.     val : function(value) {   
  370.         if (value == undefined) {   
  371.   
  372.             if (this.length) {   
  373.                 var elem = this[0];   
  374.   
  375.                 if (jQuery.nodeName(elem, 'option'))   
  376.                     return (elem.attributes.value || {}).specified   
  377.                             ? elem.value   
  378.                             : elem.text;   
  379.   
  380.                 // We need to handle select boxes special   
  381.                 if (jQuery.nodeName(elem, "select")) {   
  382.                     var index = elem.selectedIndex, values = [], options = elem.options, one = elem.type == "select-one";   
  383.   
  384.                     // Nothing was selected   
  385.                     if (index < 0)   
  386.                         return null;   
  387.   
  388.                     // Loop through all the selected options   
  389.                     for (var i = one ? index : 0, max = one   
  390.                             ? index + 1  
  391.                             : options.length;i < max; i++) {   
  392.                         var option = options[i];   
  393.   
  394.                         if (option.selected) {   
  395.                             // Get the specifc value for the option   
  396.                             value = jQuery(option).val();   
  397.   
  398.                             // We don't need an array for one selects   
  399.                             if (one)   
  400.                                 return value;   
  401.   
  402.                             // Multi-Selects return an array   
  403.                             values.push(value);   
  404.                         }   
  405.                     }   
  406.   
  407.                     return values;   
  408.   
  409.                     // Everything else, we just grab the value   
  410.                 } else  
  411.                     return (this[0].value || "").replace(/\r/g, "");   
  412.   
  413.             }   
  414.   
  415.             return undefined;   
  416.         }   
  417.   
  418.         if (value.constructor == Number)   
  419.             value += '';   
  420.   
  421.         return this  
  422.                 .each(function() {   
  423.                     if (this.nodeType != 1)   
  424.                         return;   
  425.   
  426.                     if (value.constructor == Array   
  427.                             && /radio|checkbox/.test(this.type))   
  428.                         this.checked = (jQuery.inArray(this.value, value) >= 0 || jQuery   
  429.                                 .inArray(this.name, value) >= 0);   
  430.   
  431.                     else if (jQuery.nodeName(this"select")) {   
  432.                         var values = jQuery.makeArray(value);   
  433.   
  434.                         jQuery("option"this)   
  435.                                 .each(function() {   
  436.                                     this.selected = (jQuery.inArray(this.value,   
  437.                                             values) >= 0 || jQuery.inArray(   
  438.                                             this.text, values) >= 0);   
  439.                                 });   
  440.   
  441.                         if (!values.length)   
  442.                             this.selectedIndex = -1;   
  443.   
  444.                     } else  
  445.                         this.value = value;   
  446.                 });   
  447.     },   
  448.   
  449.     // 设置每一个匹配元素的html内容。这个函数不能用于XML文档。但可以用于XHTML文档。   
  450.     // 取得第一个匹配的元素的html内容   
  451.     html : function(value) {   
  452.         return value == undefined ? (this[0] ? this[0].innerHTML : null) : this  
  453.                 .empty().append(value);// 去掉子节点,追加value   
  454.     },   
  455.   
  456.     // 将所有匹配的元素替换成指定的HTML或DOM元素。   
  457.     replaceWith : function(value) {   
  458.         return this.after(value).remove();// this.after(value),this没有变   
  459.     },   
  460.     // 获取第N个元素 。这个元素的位置是从0算起。   
  461.     eq : function(i) {   
  462.         return this.slice(i, +i + 1);   
  463.     },   
  464.   
  465.     // 代理数组的slice,同样的操作。   
  466.     slice : function() {   
  467.         return this.pushStack(Array.prototype.slice.apply(this, arguments));   
  468.     },   
  469.   
  470.     // 对于当前jquery对象中每个元素都进行callback(i,elem)的操作   
  471.     // 返回新生成的jquery对象。   
  472.     map : function(callback) {   
  473.         return this.pushStack(jQuery.map(this, function(elem, i) {   
  474.             return callback.call(elem, i, elem);   
  475.         }));   
  476.     },   
  477.   
  478.     // 把先前jQuery对象的所有元素加到当前的jQuery对象之中   
  479.     andSelf : function() {   
  480.         return this.add(this.prevObject);   
  481.     },   
  482.   
  483.     // data(name,value)   
  484.     // 在元素上存放数据,同时也返回value。   
  485.     // 如果jQuery集合指向多个元素,那将在所有元素上设置对应数据。   
  486.     // 这个函数不用建立一个新的expando,就能在一个元素上存放任何格式的数据,而不仅仅是字符串。   
  487.   
  488.     // data(name)   
  489.     // 返回元素上储存的相应名字的数据,可以用data(name, value)来设定。   
  490.     // 如果jQuery集合指向多个元素,那将只返回第一个元素的对应数据   
  491.     data : function(key, value) {   
  492.         var parts = key.split(".");   
  493.         parts[1] = parts[1] ? "." + parts[1] : "";   
  494.   
  495.         if (value === undefined) {// 取值   
  496.             // 这个特别的方法将会触发指定的事件类型上所有绑定的处理函数。但不会执行浏览器默认动作   
  497.             var data = this.triggerHandler("getData" + parts[1] + "!",   
  498.                     [parts[0]]);   
  499.   
  500.             if (data === undefined && this.length)   
  501.                 data = jQuery.data(this[0], key);   
  502.   
  503.             return data === undefined && parts[1] ? this.data(parts[0]) : data;   
  504.         } else { // 设值   
  505.             return this.trigger("setData" + parts[1] + "!", [parts[0], value])   
  506.                     .each(function() {   
  507.                         jQuery.data(this, key, value);   
  508.                     });   
  509.         }   
  510.     },   
  511.   
  512.     // 在元素上移除存放的数据   
  513.     // 与$(...).data(name, value)函数作用相反   
  514.     removeData : function(key) {   
  515.         return this.each(function() {   
  516.             jQuery.removeData(this, key);   
  517.         });   
  518.     },   
  519.   
  520.     // Dom manipulate操作的函数,对于每个jQuery对象中元素都运行   
  521.     // 由callback操作args转化成的Dom 元素集合的函数。   
  522.     domManip : function(args, table, reverse, callback) {   
  523.         var clone = this.length > 1, elems;   
  524.   
  525.         // 对当前的jquery对象中每个元素都进行操作   
  526.         return this.each(function() {   
  527.             if (!elems) {// 把args 转化为dom元素数组,追加的内容   
  528.                     elems = jQuery.clean(args, this.ownerDocument);   
  529.                     if (reverse)// 倒序   
  530.                         elems.reverse();   
  531.                 }   
  532.   
  533.                 var obj = this;   
  534.   
  535.                 // Ie Table不兼容,要进行特殊处理   
  536.                 if (table && jQuery.nodeName(this"table")// 当前元素是table?   
  537.                         && jQuery.nodeName(elems[0], "tr"))// 要追加是tr?   
  538.                     obj = this.getElementsByTagName("tbody")[0]// 没有tbody,创建追加   
  539.                             || this.appendChild(this.ownerDocument   
  540.                                     .createElement("tbody"));   
  541.   
  542.                 var scripts = jQuery([]);   
  543.   
  544.                 jQuery.each(elems, function() {   
  545.                     // 长度大于1,就采用clone。取第一个元素,否则就是本元素   
  546.                         var elem = clone ? jQuery(this).clone(true)[0] : this;   
  547.   
  548.                         // 执行所有 scripts 在所有的元素注入之后   
  549.                         if (jQuery.nodeName(elem, "script"))   
  550.                             scripts = scripts.add(elem);   
  551.                         else {   
  552.                             // 除去内部 scripts,同时保存起来, 为了之后的计算   
  553.                             if (elem.nodeType == 1)   
  554.                                 scripts = scripts.add(jQuery("script", elem)   
  555.                                         .remove());   
  556.   
  557.                             // 注册元素到document之中   
  558.                             callback.call(obj, elem);   
  559.                         }   
  560.                     });   
  561.   
  562.                 scripts.each(evalScript);   
  563.             });   
  564.     }   
  565. };   
  566.   
  567. // Give the init function the jQuery prototype for later instantiation   
  568. jQuery.fn.init.prototype = jQuery.fn;   
  569.   
  570. function evalScript(i, elem) {   
  571.     if (elem.src) {//    
  572.         jQuery.ajax( {   
  573.             url : elem.src,   
  574.             async : false,   
  575.             dataType : "script"  
  576.         });   
  577.     } else {// 对于本地的,通过globalEval运行   
  578.         jQuery   
  579.                 .globalEval(elem.text || elem.textContent || elem.innerHTML   
  580.                         || "");   
  581.     }   
  582.     if (elem.parentNode)// 除去   
  583.         elem.parentNode.removeChild(elem);   
  584. }   
  585.   
  586. function now() {   
  587.     return +new Date;   
  588. }   
  589.   
  590. jQuery.extend = jQuery.fn.extend = function() {   
  591.   
  592.     var target = arguments[0] || {}, // 第一个参数是目标   
  593.     i = 1, length = arguments.length, deep = false, options;   
  594.   
  595.     if (target.constructor == Boolean) {// 第一个参数是bool型的   
  596.         deep = target;// 深度copy   
  597.         target = arguments[1] || {};// target指向第二个参数   
  598.         i = 2;   
  599.     }   
  600.   
  601.     // target 是string 型的或?   
  602.     if (typeof target != "object" && typeof target != "function")   
  603.         target = {};   
  604.   
  605.     if (length == i) {// 只有一个参数?或deep copy 时,两个参数   
  606.         target = this;// 目标为this   
  607.         --i;   
  608.     }   
  609.   
  610.     for (;i < length; i++)   
  611.         if ((options = arguments[i]) != null)   
  612.   
  613.             for (var name in options) {   
  614.                 var src = target[name], copy = options[name];   
  615.                 if (target === copy)// 防止死循环   
  616.                     continue;   
  617.                 // 深度copy处理,最深为元素   
  618.                 if (deep && copy && typeof copy == "object" && !copy.nodeType)   
  619.                     target[name] = jQuery.extend(deep, src   
  620.                             || (copy.length != null ? [] : {}), copy);   
  621.                 else if (copy !== undefined)// 直接copy   
  622.                     target[name] = copy;   
  623.   
  624.             }   
  625.   
  626.     return target;   
  627. };   
  628.   
  629. var expando = "jQuery" + now(), uuid = 0, windowData = {},   
  630. // exclude the following css properties to add px   
  631. exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,   
  632. // cache defaultView   
  633. // defaultViewis generally a reference to the window object for the document   
  634. defaultView = document.defaultView || {};   
  635.   
  636. jQuery.extend( {   
  637.     noConflict : function(deep) {   
  638.         window.$ = _$;   
  639.   
  640.         if (deep)   
  641.             window.jQuery = _jQuery;   
  642.   
  643.         return jQuery;   
  644.     },   
  645.   
  646.     // See test/unit/core.js for details concerning this function.   
  647.         // Since 1.3 DOM methods and function like alert   
  648.         // aren't supported. They return false on IE (#2968).   
  649.         isFunction : function(fn) {   
  650.             return fn instanceof Function;   
  651.         },   
  652.   
  653.         // 判断是不是XMLDoc   
  654.         isXMLDoc : function(elem) {   
  655.             return elem.documentElement && !elem.body || elem.tagName   
  656.                     && elem.ownerDocument && !elem.ownerDocument.body;   
  657.         },   
  658.   
  659.         // Evalulates a script in a global context   
  660.         // 在全局的范围eval 代码,也就是在中   
  661.         globalEval : function(data) {   
  662.             data = jQuery.trim(data);   
  663.   
  664.             if (data) {   
  665.                 // Inspired by code by Andrea Giammarchi   
  666.                 // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html   
  667.                 var head = document.getElementsByTagName("head")[0]   
  668.                         || document.documentElement, script = document   
  669.                         .createElement("script");   
  670.   
  671.                 script.type = "text/javascript";   
  672.                 if (jQuery.browser.msie)   
  673.                     script.text = data;   
  674.                 else  
  675.                     script.appendChild(document.createTextNode(data));   
  676.   
  677.                 // Use insertBefore instead of appendChild to circumvent an IE6   
  678.                 // bug. This arises when a base node is used (#2709).   
  679.                 head.insertBefore(script, head.firstChild);   
  680.                 head.removeChild(script);   
  681.             }   
  682.         },   
  683.   
  684.         // 判断elem的nodeName是否存在   
  685.         nodeName : function(elem, name) {   
  686.             return elem.nodeName   
  687.                     && elem.nodeName.toUpperCase() == name.toUpperCase();   
  688.         },   
  689.   
  690.         cache : {},   
  691.   
  692.         data : function(elem, name, data) {   
  693.             elem = elem == window ? windowData : elem;   
  694.   
  695.             var id = elem[expando];   
  696.   
  697.             // Compute a unique ID for the element   
  698.             if (!id)   
  699.                 id = elem[expando] = ++uuid;   
  700.   
  701.             // Only generate the data cache if we're   
  702.             // trying to access or manipulate it   
  703.             if (name && !jQuery.cache[id])   
  704.                 jQuery.cache[id] = {};   
  705.   
  706.             // Prevent overriding the named cache with undefined values   
  707.             if (data !== undefined)   
  708.                 jQuery.cache[id][name] = data;   
  709.   
  710.             // Return the named cache data, or the ID for the element   
  711.             return name ? jQuery.cache[id][name] : id;   
  712.         },   
  713.   
  714.         removeData : function(elem, name) {   
  715.             elem = elem == window ? windowData : elem;   
  716.   
  717.             var id = elem[expando];   
  718.   
  719.             // If we want to remove a specific section of the element's data   
  720.             if (name) {   
  721.                 if (jQuery.cache[id]) {   
  722.                     // Remove the section of cache data   
  723.                     delete jQuery.cache[id][name];   
  724.   
  725.                     // If we've removed all the data, remove the element's cache   
  726.                     name = "";   
  727.   
  728.                     for (name in jQuery.cache[id])   
  729.                         break;   
  730.   
  731.                     if (!name)   
  732.                         jQuery.removeData(elem);   
  733.                 }   
  734.   
  735.                 // Otherwise, we want to remove all of the element's data   
  736.             } else {   
  737.                 // Clean up the element expando   
  738.                 try {   
  739.                     delete elem[expando];   
  740.                 } catch (e) {   
  741.                     // IE has trouble directly removing the expando   
  742.                     // but it's ok with using removeAttribute   
  743.                     if (elem.removeAttribute)   
  744.                         elem.removeAttribute(expando);   
  745.                 }   
  746.   
  747.                 // Completely remove the data cache   
  748.                 delete jQuery.cache[id];   
  749.             }   
  750.         },   
  751.   
  752.         // 对object中的每个对象都执行callback函数进行处理。args仅仅内部用   
  753.         each : function(object, callback, args) {   
  754.             var name, i = 0, length = object.length;   
  755.             // 和else的处理差不多,args的传参代替object的属性值   
  756.             if (args) {   
  757.                 if (length == undefined) {   
  758.                     for (name in object)   
  759.                         if (callback.apply(object[name], args) === false)   
  760.                             break;   
  761.                 } else  
  762.                     for (;i < length;)   
  763.                         if (callback.apply(object[i++], args) === false)   
  764.                             break;   
  765.   
  766.                 // A special, fast, case for the most common use of each   
  767.             } else {   
  768.                 // 不是array-like的object,对每个属性进行callback函数的调用   
  769.                 if (length == undefined) {   
  770.                     for (name in object)   
  771.                         if (callback.call(object[name], name, object[name]) === false)   
  772.                             break;   
  773.                 } else  
  774.                     // array-like object,采用数组的形式来处理   
  775.                     for (var value = object[0];i < length   
  776.                             && callback.call(value, i, value) !== false; value = object[++i]) {   
  777.                     }   
  778.             }   
  779.   
  780.             return object;   
  781.         },   
  782.   
  783.         // 根据指定元素(elem)的指定的name来修正value值,如加px,exec Fn.   
  784.         prop : function(elem, value, type, i, name) {   
  785.             if (jQuery.isFunction(value))// value=Fn   
  786.                 value = value.call(elem, i);// 得到Fn的返回value   
  787.             // 对于element的style中CSS属性,对需要加上单位的加上px单位   
  788.             return value && value.constructor == Number && type == "curCSS"  
  789.                     && !exclude.test(name) ? value + "px" : value;   
  790.         },   
  791.   
  792.         // 一组内部使用的Class操作函数   
  793.         className : {   
  794.             // 为元素增加classNameS   
  795.             add : function(elem, classNames) {// 多个className,空格分开   
  796.                 jQuery.each((classNames || "").split(/\s+/),   
  797.                         function(i, className) {   
  798.                             if (elem.nodeType == 1  
  799.                                     && !jQuery.className.has(elem.className,   
  800.                                             className))   
  801.                                 elem.className += (elem.className ? " " : "")   
  802.                                         + className;   
  803.                         });   
  804.             },   
  805.   
  806.             // 为元素除去classNames   
  807.             remove : function(elem, classNames) {   
  808.                 if (elem.nodeType == 1)// 元素   
  809.                     elem.className = classNames != undefined ? jQuery.grep(   
  810.                             elem.className.split(/\s+/), function(className) {// 过滤   
  811.                                 return !jQuery.className.has(classNames,   
  812.                                         className);   
  813.                             }).join(" ") : "";   
  814.             },   
  815.   
  816.             // 元素有没有className?   
  817.             has : function(elem, className) {   
  818.                 return jQuery.inArray(className, (elem.className || elem)   
  819.                         .toString().split(/\s+/)) > -1;   
  820.             }   
  821.         },   
  822.   
  823.         // 间隔改变elem的样式   
  824.         swap : function(elem, options, callback) {   
  825.             var old = {};   
  826.             for (var name in options) {// 替换elem.style中的属性   
  827.                 old[name] = elem.style[name];   
  828.                 elem.style[name] = options[name];   
  829.             }   
  830.             // 执行回调   
  831.             callback.call(elem);   
  832.   
  833.             // 重新换回原来的属性   
  834.             for (var name in options)   
  835.                 elem.style[name] = old[name];   
  836.         },   
  837.   
  838.         // 取得elem的name的属性值   
  839.         css : function(elem, name, force) {   
  840.             // 对元素的宽度高度修正   
  841.             if (name == "width" || name == "height") {   
  842.                 var val, props = {   
  843.                     position : "absolute",   
  844.                     visibility : "hidden",   
  845.                     display : "block"  
  846.                 }, which = (name == "width" ? ["Left""Right"] : ["Top",   
  847.                         "Bottom"]);   
  848.   
  849.                 function getWH() {// 求元素的实现高度,宽度   
  850.                     val = name == "width"  
  851.                             ? elem.offsetWidth   
  852.                             : elem.offsetHeight;   
  853.                     var padding = 0, border = 0;   
  854.                     jQuery.each(which, function() {   
  855.                         // paddinLeft,paddingRight   
  856.                             padding += parseFloat(jQuery.curCSS(elem, "padding"  
  857.                                     + thistrue))   
  858.                                     || 0;   
  859.                             // borderTopWidth,borderBottomWith   
  860.                             border += parseFloat(jQuery.curCSS(elem, "border"  
  861.                                     + this + "Width"true))   
  862.                                     || 0;   
  863.                         });   
  864.                     val -= Math.round(padding + border);   
  865.                 }   
  866.   
  867.                 if (jQuery(elem).is(":visible"))   
  868.                     getWH();   
  869.                 else  
  870.                     // 元素看不到的情况下,绝对定位,取高度或宽度   
  871.                     jQuery.swap(elem, props, getWH);   
  872.   
  873.                 return Math.max(0, val);   
  874.             }   
  875.   
  876.             return jQuery.curCSS(elem, name, force);   
  877.         },   
  878.   
  879.         curCSS : function(elem, name, force) {   
  880.             var ret, style = elem.style;   
  881.   
  882.             // elem的属性值被破坏   
  883.             function color(elem) {   
  884.                 if (!jQuery.browser.safari)   
  885.                     return false;   
  886.   
  887.                 // 从defaultView 取   
  888.                 var ret = defaultView.getComputedStyle(elem, null);   
  889.                 return !ret || ret.getPropertyValue("color") == "";   
  890.             }   
  891.   
  892.             // IE 中opacity 不兼容   
  893.             if (name == "opacity" && jQuery.browser.msie) {   
  894.                 ret = jQuery.attr(style, "opacity");   
  895.                 return ret == "" ? "1" : ret;// 1是100%的显示   
  896.             }   
  897.   
  898.             // Opera的display bug修正, 见 #2037   
  899.             if (jQuery.browser.opera && name == "display") {   
  900.                 var save = style.outline;   
  901.                 style.outline = "0 solid black";   
  902.                 style.outline = save;   
  903.             }   
  904.   
  905.             if (name.match(/float/i))// float是通过styleFloat取值的   
  906.                 name = styleFloat;   
  907.   
  908.             if (!force && style && style[name])   
  909.                 ret = style[name];// 取值   
  910.             else if (defaultView.getComputedStyle) {// 看看defaultView的CSS   
  911.   
  912.                 if (name.match(/float/i))   
  913.                     name = "float";   
  914.                 // 转换成lamb,如addMethod变成add-method   
  915.                 name = name.replace(/([A-Z])/g, "-$1").toLowerCase();   
  916.   
  917.                 var computedStyle = defaultView.getComputedStyle(elem, null);   
  918.   
  919.                 if (computedStyle && !color(elem))   
  920.                     ret = computedStyle.getPropertyValue(name);   
  921.                 else {// Safari没有正确地报道属性值,会提示none elements are involved   
  922.                     var swap = [], stack = [], a = elem, i = 0;   
  923.   
  924.                     // Locate all of the parent display: none elements   
  925.                     for (;a && color(a); a = a.parentNode)   
  926.                         stack.unshift(a);   
  927.   
  928.                     // Go through and make them visible, but in reverse   
  929.                     // (It would be better if we knew the exact display type   
  930.                     // that they had)   
  931.                     for (;i < stack.length; i++)   
  932.                         if (color(stack[i])) {   
  933.                             swap[i] = stack[i].style.display;   
  934.                             stack[i].style.display = "block";   
  935.                         }   
  936.   
  937.                     // Since we flip the display style, we have to handle that   
  938.                     // one special, otherwise get the value   
  939.                     ret = name == "display" && swap[stack.length - 1] != null  
  940.                             ? "none"  
  941.                             : (computedStyle && computedStyle   
  942.                                     .getPropertyValue(name))   
  943.                                     || "";   
  944.   
  945.                     // Finally, revert the display styles back   
  946.                     for (i = 0;i < swap.length; i++)   
  947.                         if (swap[i] != null)   
  948.                             stack[i].style.display = swap[i];   
  949.                 }   
  950.   
  951.                 // We should always get a number back from opacity   
  952.                 if (name == "opacity" && ret == "")   
  953.                     ret = "1";   
  954.   
  955.             } else if (elem.currentStyle) {// 元素的currentStyle   
  956.                 var camelCase = name.replace(/\-(\w)/g, function(all, letter) {   
  957.                     return letter.toUpperCase();   
  958.                 });   
  959.   
  960.                 ret = elem.currentStyle[name] || elem.currentStyle[camelCase];   
  961.   
  962.                 // From the awesome hack by Dean Edwards   
  963.                 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291   
  964.   
  965.                 // If we're not dealing with a regular pixel number   
  966.                 // but a number that has a weird ending, we need to convert it   
  967.                 // to pixels   
  968.                 if (!/^\d+(px)?$/i.test(ret) && /^\d/.test(ret)) {   
  969.                     // Remember the original values   
  970.                     var left = style.left, rsLeft = elem.runtimeStyle.left;   
  971.   
  972.                     // Put in the new values to get a computed value out   
  973.                     elem.runtimeStyle.left = elem.currentStyle.left;   
  974.                     style.left = ret || 0;   
  975.                     ret = style.pixelLeft + "px";   
  976.   
  977.                     // Revert the changed values   
  978.                     style.left = left;   
  979.                     elem.runtimeStyle.left = rsLeft;   
  980.                 }   
  981.             }   
  982.   
  983.             return ret;   
  984.         },   
  985.   
  986.         // 把html转换成Dom元素,elems多个html string 的数组   
  987.         clean : function(elems, context) {   
  988.             var ret = [];   
  989.             context = context || document;   
  990.             // !context.createElement fails in IE with an error but returns   
  991.             // typeof 'object'   
  992.             if (typeof context.createElement == 'undefined')   
  993.                 // 处理context是jquery对象或数组的兼容。context可以是元素,或元素的集合,或空   
  994.                 context = context.ownerDocument || context[0]   
  995.                         && context[0].ownerDocument || document;   
  996.   
  997.             jQuery   
  998.                     .each(elems, function(i, elem) {   
  999.                         if (typeof elem == 'number')   
  1000.                             elem += '';// 把int 转换成string的最高效的方法   
  1001.   
  1002.                         if (!elem)   
  1003.                             return;// 为'',undefined,false等时返回   
  1004.   
  1005.                         // 转换html为Dom元素   
  1006.                         if (typeof elem == "string") {   
  1007.                             // Fix "XHTML"-style tags in all browsers   
  1008.                             // 对于其它的标签,修改成xml的格式   
  1009.                             elem = elem   
  1010.                                     .replace(   
  1011.                                             /(<(\w+)[^>]*?)\/>/g,// front=(<(\w+)[^>]*?)   
  1012.                                             function(all, front, tag) {   
  1013.                                                 return tag   
  1014.                                                         .match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)   
  1015.                                                         ? all   
  1016.                                                         : front + "> + tag   
  1017.                                                                 + ">";   
  1018.                                             });   
  1019.   
  1020.                             // 去空格,否则indexof可能会出不能正常工作   
  1021.                             var tags = jQuery.trim(elem).toLowerCase(), div = context   
  1022.                                     .createElement("div");   
  1023.                             // 有些标签必须是有一些约束的,比如  
  1024.                             // 下面的代码在大部分是对中子元素进行修正。数组中第一个元素为深度   
  1025.                             var wrap = !tags.indexOf(")   
  1026.                                     && [1"",   
  1027.                                             ""]   
  1028.                                     || !tags.indexOf(")   
  1029.                                     && [1"
    ""
    "
    ]   
  1030.                                     || tags   
  1031.                                             .match(/^<(thead|tbody|tfoot|colg|cap)/)   
  1032.                                     && [1"
  1033. ""
    "
    ]   
  1034.                                     || !tags.indexOf(")   
  1035.                                     && [2"""
    "
    ]   
  1036.                                     || (!tags.indexOf(") || !tags   
  1037.                                             .indexOf("))   
  1038.                                     && [3"",   
  1039.                                             "
  1040. "
    ]   
  1041.                                     || !tags.indexOf(")   
  1042.                                     && [2"",   
  1043.                                             "
  1044. "
    ]   
  1045.                                     ||   
  1046.   
  1047.                                     // IE can't serialize  and 

你可能感兴趣的:(JQuery/Js)