- **
- * author:prk
- * date:2008-08-05
- * comment:analeyse the core of jquery1.2.6
- *
- */
- /*
- * jQuery
- *
- * @VERSION - New Wave Javascript
- *
- * Copyright (c) 2008 John Resig (jquery.com) Dual licensed under the MIT
- * (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
- *
- * $Date: 2008-07-24 01:00:32 +0800 (Thu, 24 Jul 2008) $ $Rev: 5793 $
- */
- // Map over jQuery in case of overwrite
- var _jQuery = window.jQuery,
- // Map over the $ in case of overwriteff
- _$ = window.$;
- var jQuery = window.jQuery = window.$ = function(selector, context) {
- // The jQuery object is actually just the init constructor 'enhanced'
- return new jQuery.fn.init(selector, context);
- };
- // A simple way to check for HTML strings or ID strings
- // (both of which we optimize for)
- var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
- // Is it a simple selector
- isSimple = /^.[^:#\[\.]*$/,
- // Will speed up references to undefined, and allows munging its name.
- undefined;
- jQuery.fn = jQuery.prototype = {
- init : function(selector, context) {
- selector = selector || document;// 确定selector存在
- // 第一种情况 Handle $(DOMElement)单个Dom 元素,忽略上下文
- if (selector.nodeType) {
- this[0] = selector;
- this.length = 1;
- return this;
- }
- if (typeof selector == "string") {//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)) {
- if (match[1])// 第二种情况处理$(html) -> $(array)
- selector = jQuery.clean([match[1]], context);
- else {// 第三种情况:HANDLE: $("#id")//处理$("#id")
- var elem = document.getElementById(match[3]);
- // Make sure an element was located
- if (elem) {
- // Handle the case where IE and Opera return items
- // by name instead of ID
- if (elem.id != match[3])
- return jQuery().find(selector);// 默认是document.find()
- // Otherwise, we inject the element directly into the
- // jQuery object
- return jQuery(elem);
- }
- selector = [];
- }
- } else
- // 第四种情况:处理$(expr, [context])==$(content).find(expr)
- return jQuery(context).find(selector);
- } else if (jQuery.isFunction(selector))
- // 第五种情况:处理$(function)七Shortcut for document ready
- return jQuery(document)[jQuery.fn.ready ? "ready" : "load"](selector);
- // 第六种情况:处理$(elements)
- return this.setArray(jQuery.makeArray(selector));
- },
- // 当前的版本号
- jquery : "@VERSION",
- // jquery对象中的元素的个数。jquery像数组。能通过$('p')[0]去取得Dom对象。
- size : function() {
- return this.length;
- },
- // jquery对象的元素的个数
- length : 0,
- // 取到本jquery对象的第几个Dom元素,无参数,代表全部的Dom元素
- get : function(num) {
- return num == undefined ? jQuery.makeArray(this) : this[num];
- },
- // 采用jQuery构建新对象,同时引用老对象。
- pushStack : function(elems) {
- var ret = jQuery(elems);// 构建新的jquery对象
- ret.prevObject = this;// 保存老的对象的引用
- return ret;
- },
- // 把array-like对象的元素全部push当前jquery对象。
- setArray : function(elems) {
- this.length = 0;
- Array.prototype.push.apply(this, elems);
- return this;
- },
- // 当前jquery对象中每个元素都执行callback(index,elem)函数
- each : function(callback, args) {// 返回this
- // 其调用了jQuery的静态方法。prototype中的mothodize是解决这类问题的好方法
- return jQuery.each(this, callback, args);
- },
- // 找到elem在本jquery对象的位置(index)
- index : function(elem) {
- var ret = -1;
- return jQuery.inArray( // 如是jQuery对象就取第一个元素
- elem && elem.jquery ? elem[0] : elem, this);
- },
- // attr(properties)
- // 将“名/值”形式的对象设置为所有匹配元素的属性。
- // attr(name)
- // 取得第一个匹配元素的属性值。通过这个方法可以方便地从第一个匹配元素中获取一个属性的值。如果元素没有相应属性,则返回 undefined 。
- // attr(key,value)
- // 为所有匹配的元素设置一个属性值。$("img").attr("src","test.jpg");
- // attr(key,fn)
- // 为所有匹配的元素设置一个由这个函数计算的值做属性值。
- attr : function(name, value, type) {
- var options = name;// 支持"名/值"形式的对象和string
- if (name.constructor == String)
- if (value === undefined)
- // 调用curCss,attr静态方法返回本对象第一个元素的name的属性值
- return this[0] && jQuery[type || "attr"](this[0], name);
- else {// 设定属性值,把name String 转换成"名/值"对象,便于统一的处理
- options = {};
- options[name] = value;
- }
- return this.each(function(i) {// 为每个元素的指定的name属性设值
- for (name in options)
- // value=options[name],可以是Fn(index),this-->each elem
- jQuery.attr(type ? this.style : this, name, jQuery
- .prop(this, options[name], type, i, name));
- });
- },
- // css(name)
- // 访问第一个匹配元素的样式属性。
- // css(name,value)
- // 在所有匹配的元素中,设置一个样式属性的值。数字将自动转化为像素值
- // css(properties)
- // 把一个“名/值对”对象设置为所有匹配元素的样式属性。这是一种在所有匹配的元素上设置大量样式属性的最佳方式。
- css : function(key, value) {
- if ((key == 'width' || key == 'height') && parseFloat(value) < 0)
- value = undefined;// 忽略负数
- return this.attr(key, value, "curCSS");// 调用了curCSS方法
- },
- // text()
- // 取得所有匹配元素的内容。结果是由所有匹配元素包含的文本内容组合起来的文本。这个方法对HTML和XML文档都有效。
- // text(val)
- // 设置所有匹配元素的文本内容.与 html() 类似, 但将编码 HTML (将 "<" 和 ">" 替换成相应的HTML实体).
- text : function(text) {
- if (typeof text != "object" && text != null)
- return this.empty()// 除去所有的子元素,加上创建的文本节点
- .append((this[0] && this[0].ownerDocument || document)
- .createTextNode(text));
- var ret = "";
- jQuery.each(text || this, function() {// 所有匹配元素包含的文本内容组合起来
- jQuery.each(this.childNodes, function() {
- if (this.nodeType != 8)// 8:注释
- ret += (this.nodeType != 1// 元素的话,递归子元素
- ? this.nodeValue
- : jQuery.fn.text([this]));
- });
- });
- return ret;
- },
- // *****************************************************************************
- // 一组用于元素标签包裹操作的函数
- // 将所有匹配的元素用单个元素包裹起来
- // 这个函数的原理是检查提供的第一个元素并在它的代码结构中找到最上层的祖先元素--这个祖先元素就是包装元素。
- // 这于 '.wrap()' 是不同的,'.wrap()'为每一个匹配的元素都包裹一次。
- wrapAll : function(html) {
- if (this[0])
- /*
- *
Hello
cruel
World
。--> - * $("p").wrapAll("");-->调用wrapAll的jQuery对象,称:A。有三个元素。
- * 第一步:复制生成一个jQuery对象,称:B。得到:的元素。
- * 第二步:把B所有的元素都插在A[0]元素之前,得到
Hello
cruel
World
- * 第三步:找到B对象中所有元素的最内面的节点,如
- * 第四步:向所有innerNode内部插入A对象的所有元素,得到
Hello
cruel
World
- */
- jQuery(html, this[0].ownerDocument).clone().insertBefore(this[0])
- .map(function() {// 找到当前元素的最下层的子节点
- var elem = this;
- while (elem.firstChild)
- elem = elem.firstChild;
- return elem;
- }).append(this);// this指是调用wrapAll的jQuery对象。
- return this;
- },
- // 将每一个匹配的元素的子内容(包括文本节点)用一个HTML结构包裹起来
- wrapInner : function(html) {
- return this.each(function() {// 这里包裹的对象是每个元素的对象的contents()
- jQuery(this).contents().wrapAll(html);
- });
- },
- // 对于当前的jquery对象的每个元素都执行wrapAll(html)
- wrap : function(html) {
- return this.each(function() {// 这里包裹的对象是每个元素的对象
- jQuery(this).wrapAll(html);
- });
- },
- // ************************************************************************
- // ******************************************************************
- // 该组方法主要是完成把元素插到什么地方,与Ext的DomHelp的功能相似。
- // 在一个元素之前,之后,元素的开始,结束位置
- // 向每个匹配的元素内部追加内容。
- // 这个操作与对指定的元素执行appendChild方法,将它们添加到文档中的情况类似
- append : function() {
- return this.domManip(arguments, true, false, function(elem) {
- if (this.nodeType == 1)
- this.appendChild(elem);
- });
- },
- // 向每个匹配的元素内部前置内容。
- // 这是向所有匹配元素内部的开始处插入内容的最佳方式。
- prepend : function() {// elem =arguments的转化集合中的dom元素
- return this.domManip(arguments, true, true, function(elem) {
- if (this.nodeType == 1)// this=jQuery对象的每个元素(对于tr之类会修正)
- this.insertBefore(elem, this.firstChild);
- });
- },
- // 在每个匹配的元素之前插入内容。
- before : function() {
- return this.domManip(arguments, false, false, function(elem) {
- this.parentNode.insertBefore(elem, this);// this=jQuery对象的每个元素
- });
- },
- // 在每个匹配的元素之后插入内容
- after : function() {
- return this.domManip(arguments, false, true, function(elem) {
- this.parentNode.insertBefore(elem, this.nextSibling);
- });
- },
- // ******************************************************************
- // 回到最近的一个"破坏性"操作之前。即,将匹配的元素列表变为前一次的状态。
- end : function() {
- return this.prevObject || jQuery([]);
- },
- // 搜索所有与指定表达式匹配的元素。这个函数是找出正在处理的元素的后代元素的好方法。
- // 所有搜索都依靠jQuery表达式来完成。这个表达式可以使用CSS1-3的选择器语法来写。
- find : function(selector) {
- var elems = jQuery.map(this, function(elem) {// 找到每个元素的满足的
- return jQuery.find(selector, elem);
- });
- return this.pushStack(/[^+>] [^+>]/.test(selector) ? jQuery
- .unique(elems) : elems);// 是不是返回不重复的元素?
- },
- // clone当前对象,events表明是否clone事件
- clone : function(events) {
- // 对每个元素都进行加工(copy)后的集合重新构建jQuery对象
- var ret = this.map(function() {
- if (jQuery.browser.msie && !jQuery.isXMLDoc(this)) {
- // IE 中cloneNode不能copy 通过attachEvent增加的事件
- // 而innserHTML不能copy一些修改过的属性(仅作为属性储存)如input 的name
- var clone = this.cloneNode(true), container = document
- .createElement("div");
- container.appendChild(clone);
- return jQuery.clean([container.innerHTML])[0];
- } else
- return this.cloneNode(true);
- });
- // Need to set the expando to null on the cloned set if it exists
- // removeData doesn't work here, IE removes it from the original as well
- // this is primarily for IE but the data expando shouldn't be copied
- // over in any browser
- var clone = ret.find("*").andSelf().each(function() {
- if (this[expando] != undefined)
- this[expando] = null;
- });
- if (events === true)// clone所有事件
- this.find("*").andSelf().each(function(i) {
- if (this.nodeType == 3)
- return;
- var events = jQuery.data(this, "events");
- for (var type in events)
- for (var handler in events[type])
- jQuery.event.add(clone[i], type, events[type][handler],
- events[type][handler].data);
- });
- return ret;
- },
- // 筛选出与指定表达式匹配的元素集合。可以通过函数来筛选当前jQuery对象的
- // 元素,还有通过用逗号分隔多个表达式来筛选
- filter : function(selector) {// grep,multiFilter的综合
- return this.pushStack(jQuery.isFunction(selector)
- && jQuery.grep(this, function(elem, i) {
- return selector.call(elem, i);
- }) || jQuery.multiFilter(selector, this));
- },
- // 删除与指定表达式匹配的元素
- not : function(selector) {
- if (selector.constructor == String)// 采用jQuery表达式
- if (isSimple.test(selector))
- return this.pushStack(jQuery.multiFilter(selector, this, true));
- else
- // 多表达式要过滤
- selector = jQuery.multiFilter(selector, this);
- var isArrayLike = selector.length// array-like的集合?
- && selector[selector.length - 1] !== undefined
- && !selector.nodeType;
- return this.filter(function() {// 过滤掉return false的元素
- return isArrayLike ? jQuery.inArray(this, selector) < 0// this在selector中?
- : this != selector;
- });
- },
- // 把与表达式匹配的元素添加到jQuery对象中。array(-like)的集合也可以追加进来
- add : function(selector) {
- return this.pushStack(jQuery.unique(jQuery.merge(this.get(),
- typeof selector == 'string' ? jQuery(selector) : jQuery
- .makeArray(selector))));
- },
- // 用一个表达式来检查当前选择的元素集合,如果其中至少有一个元素符合这个给定的表达式就返回true。
- is : function(selector) {
- return !!selector && jQuery.multiFilter(selector, this).length > 0;
- },
- // 检查当前的元素是否含有某个特定的类,如果有,则返回true
- hasClass : function(selector) {
- return this.is("." + selector);
- },
- // 获得第一个匹配元素的当前值。
- // 在 jQuery 1.2 中,可以返回任意元素的值了。包括select。如果多选,将返回一个数组,其包含所选的值。
- // 设置每一个匹配元素的值。在 jQuery 1.2, 这也可以为select元件赋值
- val : function(value) {
- if (value == undefined) {
- if (this.length) {
- var elem = this[0];
- if (jQuery.nodeName(elem, 'option'))
- return (elem.attributes.value || {}).specified
- ? elem.value
- : elem.text;
- // We need to handle select boxes special
- if (jQuery.nodeName(elem, "select")) {
- var index = elem.selectedIndex, values = [], options = elem.options, one = elem.type == "select-one";
- // Nothing was selected
- if (index < 0)
- return null;
- // Loop through all the selected options
- for (var i = one ? index : 0, max = one
- ? index + 1
- : options.length;i < max; i++) {
- var option = options[i];
- if (option.selected) {
- // Get the specifc value for the option
- value = jQuery(option).val();
- // We don't need an array for one selects
- if (one)
- return value;
- // Multi-Selects return an array
- values.push(value);
- }
- }
- return values;
- // Everything else, we just grab the value
- } else
- return (this[0].value || "").replace(/\r/g, "");
- }
- return undefined;
- }
- if (value.constructor == Number)
- value += '';
- return this
- .each(function() {
- if (this.nodeType != 1)
- return;
- if (value.constructor == Array
- && /radio|checkbox/.test(this.type))
- this.checked = (jQuery.inArray(this.value, value) >= 0 || jQuery
- .inArray(this.name, value) >= 0);
- else if (jQuery.nodeName(this, "select")) {
- var values = jQuery.makeArray(value);
- jQuery("option", this)
- .each(function() {
- this.selected = (jQuery.inArray(this.value,
- values) >= 0 || jQuery.inArray(
- this.text, values) >= 0);
- });
- if (!values.length)
- this.selectedIndex = -1;
- } else
- this.value = value;
- });
- },
- // 设置每一个匹配元素的html内容。这个函数不能用于XML文档。但可以用于XHTML文档。
- // 取得第一个匹配的元素的html内容
- html : function(value) {
- return value == undefined ? (this[0] ? this[0].innerHTML : null) : this
- .empty().append(value);// 去掉子节点,追加value
- },
- // 将所有匹配的元素替换成指定的HTML或DOM元素。
- replaceWith : function(value) {
- return this.after(value).remove();// this.after(value),this没有变
- },
- // 获取第N个元素 。这个元素的位置是从0算起。
- eq : function(i) {
- return this.slice(i, +i + 1);
- },
- // 代理数组的slice,同样的操作。
- slice : function() {
- return this.pushStack(Array.prototype.slice.apply(this, arguments));
- },
- // 对于当前jquery对象中每个元素都进行callback(i,elem)的操作
- // 返回新生成的jquery对象。
- map : function(callback) {
- return this.pushStack(jQuery.map(this, function(elem, i) {
- return callback.call(elem, i, elem);
- }));
- },
- // 把先前jQuery对象的所有元素加到当前的jQuery对象之中
- andSelf : function() {
- return this.add(this.prevObject);
- },
- // data(name,value)
- // 在元素上存放数据,同时也返回value。
- // 如果jQuery集合指向多个元素,那将在所有元素上设置对应数据。
- // 这个函数不用建立一个新的expando,就能在一个元素上存放任何格式的数据,而不仅仅是字符串。
- // data(name)
- // 返回元素上储存的相应名字的数据,可以用data(name, value)来设定。
- // 如果jQuery集合指向多个元素,那将只返回第一个元素的对应数据
- data : function(key, value) {
- var parts = key.split(".");
- parts[1] = parts[1] ? "." + parts[1] : "";
- if (value === undefined) {// 取值
- // 这个特别的方法将会触发指定的事件类型上所有绑定的处理函数。但不会执行浏览器默认动作
- var data = this.triggerHandler("getData" + parts[1] + "!",
- [parts[0]]);
- if (data === undefined && this.length)
- data = jQuery.data(this[0], key);
- return data === undefined && parts[1] ? this.data(parts[0]) : data;
- } else { // 设值
- return this.trigger("setData" + parts[1] + "!", [parts[0], value])
- .each(function() {
- jQuery.data(this, key, value);
- });
- }
- },
- // 在元素上移除存放的数据
- // 与$(...).data(name, value)函数作用相反
- removeData : function(key) {
- return this.each(function() {
- jQuery.removeData(this, key);
- });
- },
- // Dom manipulate操作的函数,对于每个jQuery对象中元素都运行
- // 由callback操作args转化成的Dom 元素集合的函数。
- domManip : function(args, table, reverse, callback) {
- var clone = this.length > 1, elems;
- // 对当前的jquery对象中每个元素都进行操作
- return this.each(function() {
- if (!elems) {// 把args 转化为dom元素数组,追加的内容
- elems = jQuery.clean(args, this.ownerDocument);
- if (reverse)// 倒序
- elems.reverse();
- }
- var obj = this;
- // Ie Table不兼容,要进行特殊处理
- if (table && jQuery.nodeName(this, "table")// 当前元素是table?
- && jQuery.nodeName(elems[0], "tr"))// 要追加是tr?
- obj = this.getElementsByTagName("tbody")[0]// 没有tbody,创建追加
- || this.appendChild(this.ownerDocument
- .createElement("tbody"));
- var scripts = jQuery([]);
- jQuery.each(elems, function() {
- // 长度大于1,就采用clone。取第一个元素,否则就是本元素
- var elem = clone ? jQuery(this).clone(true)[0] : this;
- // 执行所有 scripts 在所有的元素注入之后
- if (jQuery.nodeName(elem, "script"))
- scripts = scripts.add(elem);
- else {
- // 除去内部 scripts,同时保存起来, 为了之后的计算
- if (elem.nodeType == 1)
- scripts = scripts.add(jQuery("script", elem)
- .remove());
- // 注册元素到document之中
- callback.call(obj, elem);
- }
- });
- scripts.each(evalScript);
- });
- }
- };
- // Give the init function the jQuery prototype for later instantiation
- jQuery.fn.init.prototype = jQuery.fn;
- function evalScript(i, elem) {
- if (elem.src) {//