欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

jQuery 1.5 源碼解讀 面向中高階JSER

 更新時(shí)間:2011年04月05日 20:46:09   作者:  
jQuery 1.5 源碼有8068行。很多想讀 jQuery 源碼的童鞋在讀了一半不到就不敢往下讀了,jQuery是一個(gè) 封裝良好、代碼緊湊 的框架。
幾乎很難從jQuery分離其中的一部分功能。所以在這里我分享下應(yīng)該讀 jQuery 源碼的一些成果,以及讀源碼的方法??写a是必須的。

1. 代碼折疊是必須的。

因此必須在支持語法折疊的編輯器里打開源碼。 根據(jù)折疊層次,我們可以很快知道: 所有 jQuery 的代碼都在一個(gè)函數(shù)中:   

(function( window, undefined ) {
// jQuery 代碼

})(window);

這樣可以避免內(nèi)部對象污染全局。傳入的參數(shù)1是 window, 參數(shù)2是 undefined , 加快js搜索此二對象的速度。

2.  接著打開第一級折疊。

可以發(fā)現(xiàn) jQuery 代碼是按這樣順序來組織:

  • 定義 jQuery 函數(shù) ( 代碼  20 - 1081 行)
  • 生成 jQuery.support (代碼 1083 - 1276 行)
  • 和 data 有關(guān)擴(kuò)展 (代碼 1279 - 1510 行)
  • 和隊(duì)列有關(guān)擴(kuò)展 (代碼 1514 - 1605 行)
  • 和屬性有關(guān)擴(kuò)展 (代碼 1609 - 1988 行)
  • 和事件有關(guān)擴(kuò)展 (代碼 1993 - 3175 行)
  • 內(nèi)部的Sizzle CSS Selector Engine (代碼 3183 - 4518 行)
  • 和節(jié)點(diǎn)有關(guān)擴(kuò)展 (代碼 4520 - 5492 行)
  • 和樣式有關(guān)擴(kuò)展 (代碼 5497 - 5825 行)
  • 和ajax有關(guān)擴(kuò)展 (代碼 5830 - 7172 行)
  • 和效果有關(guān)擴(kuò)展 (代碼 7176 - 7696 行)
  • 和定位有關(guān)擴(kuò)展 (代碼 7700 - 8065 行)

下面的模塊可以用上面的模塊,上面的模塊不需要下面的模塊

3.   定義 jQuery 函數(shù) ( 代碼  20 - 1081 行)

總的代碼是這樣的框架:

var jQuery = (function() {
// 創(chuàng)建 jQuery 對象
var jQuery = function( selector, context ) {
//

};

// 創(chuàng)建 jQuery.fn 對象
jQuery.fn = jQuery.prototype = {
//
};

// 聲明 jQuery.extend
jQuery.extend = jQuery.fn.extend = function() {
//
};

// 使用 jQuery.extend 擴(kuò)展自己
jQuery.extend({
//

});

// 瀏覽器方面的一些瑣碎
//

// 定義全局對象
return (window.jQuery = window.$ = jQuery);

})();

從這里知道: 平時(shí)所用的 $ 其實(shí)就是 jQuery 函數(shù)的別名。

3.1 jQuery對象 (代碼 23 - 26 行)

  jQuery對象似乎一直都是這東西:

var jQuery = function( selector, context ) {
// 實(shí)際上 jQuery 對象是 jQuery.fn.init 返回的。
return new jQuery.fn.init( selector, context, rootjQuery );
}

這個(gè)函數(shù)表示: 要想知道函數(shù) jQuery 是什么東西,必須看   jQuery.fn.init  對象。

同時(shí)這也解釋了為什么寫代碼不需要 new jQuery。

再看第29行 - 97行, 都是一些變量聲明,這些變量在下面的函數(shù)用到。提取變量的好處: 對正則節(jié)約編譯的時(shí)間, 同時(shí)能在壓縮的時(shí)候獲得更小的結(jié)果。

3.2 jQuery.fn 對象 (代碼 99 - 320 行)

這個(gè)fn 其實(shí)是 jQuery.prototype ,這也是為啥jQuery.fn 就是擴(kuò)展 jQuery對象的唯一原因。

肯能有人會疑問, jQuery 返回 new jQuery.fn.init, 也就是說,平時(shí)的函數(shù)應(yīng)該是 jQuery.fn.init.prototype 所有的成員,不是 jQuery.prototype 成員。當(dāng)然原因也很簡單: jQuery.fn.init.prototype === jQuery.prototype (代碼 322  行)

jQuery 對js對象處理和中國人講話一樣繞。這里總結(jié)下到底 jQuery 對象是個(gè)什么家伙。

jQuery 是普通函數(shù), 返回 jQuery.fn.init 對象的實(shí)例( new jQuery.fn.init() )。

然后 jQuery.fn === jQuery.prototype === jQuery.fn.init.prototype ,最后, jQuery返回的對象的成員和 jQuery.fn 的成員匹配。

jQuery.fn 下有很多成員,下面稍作介紹:

  init - 初始化(下詳細(xì)說明)

  constructor - 手動指定一個(gè)構(gòu)造函數(shù)。 因?yàn)槟J(rèn)是  jQuery.fn.init

  length - 讓這個(gè)對象更接近一個(gè) 原生的數(shù)組

  size - 返回 length

  toArray - 通過 Array.prototype slice 實(shí)現(xiàn)生成數(shù)組

  get - 即 this[ num ] ,當(dāng)然作了下 參數(shù)索引 的處理。

  pushStack - 加入一個(gè)元素

  ready - 瀏覽器加載后執(zhí)行(下詳細(xì)說明)

  end - 通過保存的 prevObject 重新返回

  each - 參考 http://www.cnblogs.com/Fooo/archive/2011/01/11/1932900.html

參考 http://www.cnblogs.com/rubylouvre/archive/2009/11/21/1607632.html

3.3 jQuery.fn.init (代碼 101 - 211 行)

  jQuery.fn.init 就是所謂的 $ 函數(shù)。 也就是說,平常的 $("#id") 就是  new jQuery.fn.init("#id");

這個(gè)函數(shù)很長,但代碼覆蓋率小。

init: function( selector, context, rootjQuery ) {
// 參數(shù): selector 選擇器
// context 上下文
// rootjQuery 父節(jié)點(diǎn)

// 處理 $("")、 $(null) 和 $(undefined)
if ( !selector ) {
return this;
}

// 處理 $(DOMElement)
if ( selector.nodeType ) {

// 直接扔數(shù)組中, 就搞定了。
this.context = this[0] = selector;
this.length = 1;
return this;
}

// 處理 $("body") body 元素只存在一次,單獨(dú)找它
if ( selector === "body" && !context && document.body ) {

// 同樣扔數(shù)組中, 順便把 selector 更新更新。
this.context = document;
this[0] = document.body;
thisis.selector
= "body";
this.length = 1;
return this;
}

// 處理 $(HTML 代碼 或者是 css 選擇器)
if ( typeof selector === "string" ) {
//

// 處理 $(函數(shù))
} else if ( jQuery.isFunction( selector ) ) {

// 如果是函數(shù),則執(zhí)行 $(document).ready , 這樣 $(document).ready(func) 簡為 $(func)
return rootjQuery.ready( selector );
}

// 略。

// 如果傳入的是一個(gè) Dom列表 ( getElementsByTagName 結(jié)果 ) 則轉(zhuǎn)為 jQuery 數(shù)組。
return jQuery.makeArray( selector, this );
}
// 這部分代碼是 上段中 略 的 也就是說是 jQuery(字符串) 處理。

// 檢查是否字符串是常用選擇器 (/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/)
match = quickExpr.exec( selector );

// 檢查是否正確匹配
if ( match && (match[1] || !context) ) {

// 處理: $(html) -> $(array)
if ( match[1] ) {

// 獲取正文,默認(rèn) document
context = context instanceof jQuery ? context[0] : context;
doc
= (context ? context.ownerDocument || context : document);

// 如果傳入簡單的 "<標(biāo)簽>", ( /^<(\w+)\s*\/?>(?:<\/\1>)?$/)
ret = rsingleTag.exec( selector );

// 返回 createElement("tag")

return jQuery.merge( this, selector );

// 處理: $("#id")
} else {
elem
= document.getElementById( match[2] );

// 因?yàn)橛械臑g覽器 getElementById 不只返回 id匹配的,所以做檢查。
return this;
}

// 處理 $("標(biāo)簽")
} else if ( !context && !rnonword.test( selector ) ) {
this.selector = selector;
this.context = document;
selector
= document.getElementsByTagName( selector );
return jQuery.merge( this, selector );

//處理: $(選擇器, $(...))
} else if ( !context || context.jquery ) {
return (context || rootjQuery).find( selector );

// 處理: $(選擇器, 上下文)
// (相當(dāng)于: $(上下文).find(選擇器)
} else {
return this.constructor( context ).find( selector );
}

3.4 jQuery.fn.extend (代碼 324 - 386 行)

這個(gè)函數(shù)用于 擴(kuò)展函數(shù)

函數(shù)中含多個(gè)參數(shù)判斷,為了使用可以更靈活。

基本原理就是for(in),這里不具體介紹了。

3.5 jQuery.noConflict (代碼 389 - 399 行 )
noConflict: function( deep ) {
window.$
= _$;

if ( deep ) {
window.jQuery
= _jQuery;
}

return jQuery;
},

不多解釋了,就是讓 jQuery 恢復(fù)為全局的對象。

3.6 jQuery.ready (代碼 407 -381 行)

 其中有2個(gè)函數(shù):

jQuery.ready 觸發(fā)執(zhí)行 readyList 中的所有函數(shù)

jQuery.bindReady  初始化讓 jQuery.ready 成功執(zhí)行

bindReady: function() {

// 如果已經(jīng)執(zhí)行 bindReady 則返回。
if ( readyBound ) {
return;
}

readyBound
= true;

// 如果頁面已經(jīng)加載, 馬上執(zhí)行 jQuery.ready
if ( document.readyState === "complete" ) {
return setTimeout( jQuery.ready, 1 );
}

// 標(biāo)準(zhǔn)瀏覽器支持 DOMContentLoaded
if ( document.addEventListener ) {
// 你懂的
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

// 為什么還要 load ? , 因?yàn)橛行r(shí)候 DOMContentLoaded 失敗(如 iframe) ,而 load 總是會成功, 所以,同時(shí)處理 DOMContentLoaded load, 在 jQuery.ready 中會刪除監(jiān)聽函數(shù),保證最后這個(gè)函數(shù)只執(zhí)行一次
window.addEventListener( "load", jQuery.ready, false );

// IE瀏覽器( IE 8 以下)
} else if ( document.attachEvent ) {

// 使用 onreadystatechange
document.attachEvent("onreadystatechange", DOMContentLoaded);

// 同理
window.attachEvent( "onload", jQuery.ready );

// 如果 IE 下且非 iframe, 這里有個(gè)技巧。 見 doScrollCheck();
// 原理: 瀏覽器在沒加載時(shí) 設(shè)置 scrollLeft 會錯(cuò)誤,所喲每隔1秒廁所 是否 scrollLeft 成功,如果發(fā)現(xiàn)成功,則執(zhí)行 jQuery.ready 。但這只對非 frame 會有用。
var toplevel = false;

try {
toplevel
= window.frameElement == null;
}
catch(e) {}

if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
},

bindReady 函數(shù)在執(zhí)行 ready 時(shí)執(zhí)行。(jQuery 1.4 之前版本都是 絕對執(zhí)行,不管需不需要 ready 函數(shù))

4.  生成 jQuery.support (代碼 1083 - 1276 行)

   人人都說 jQuery.support 是個(gè)好東西。確實(shí),這東西可以解決很多兼容問題。

    jQuery.support 是基于檢測的瀏覽器兼容方式。也就是說,創(chuàng)建一個(gè)元素, 看這個(gè)元素是否符合一些要求。

  比如測試元素是否支持checkOn屬性,只要先 set check = 'on' 然后看瀏覽器是否 get check == 'on'。

  此部分源碼不具體介紹了。

5.和 data 有關(guān)擴(kuò)展 (代碼 1279 - 1510 行)

     jQuery的 data() 用于存儲一個(gè)字典。而這些數(shù)據(jù)最后都保存在 jQuery.cache  ( 代碼 1283 行) ,  全局對象存在 windowData  ( 代碼 1279  行)  。

   但如果正確根據(jù)對象找到其在 jQuery.cache  的存儲對象? 這就是 expando 字符串。

比如一個(gè)對象:  elem 。

滿足:   elem.expando = "jQuery12321";

那么    jQuery.cache["jQuery12321"]  就是存儲這個(gè) elem 數(shù)據(jù)的對象。

實(shí)際上, 不是 elem.expando 表示鍵值,而是 elem[ jQuery.expando ] 表示。

而一個(gè)對象數(shù)據(jù)又是一個(gè)字典,所以最后執(zhí)行 jQuery.data(elem, 'events') 后就是:

jQuery.cache[elem[jQuery.expando]]['events'] 的內(nèi)容   (jQuery.cache[elem[jQuery.expando]] = {} )

6.和隊(duì)列有關(guān)擴(kuò)展 (代碼 1514 - 1605 行)

隊(duì)列是 jQuery 1.5 新增的。

主要用于特效等需要等待執(zhí)行的時(shí)候。

隊(duì)列主要操作就是 進(jìn)隊(duì)queue 出隊(duì)dequeue

jQuery 隊(duì)列內(nèi)的數(shù)據(jù):

如果沒有執(zhí)行:

[將執(zhí)行的1, 將執(zhí)行的2]

現(xiàn)在開始執(zhí)行 <將執(zhí)行的1>, 如果 type 為空或 "fx", 隊(duì)列內(nèi)數(shù)據(jù):

["inprogress", 將執(zhí)行的2]

執(zhí)行完之后:

["將執(zhí)行的2]

以上的這些數(shù)據(jù)都存在 jQuery.data(obj, (type || "fx") + "queue") (代碼 1520 - 1522行)

jQuery.delay 則用于延時(shí)執(zhí)行一個(gè)函數(shù)。相當(dāng)于把原來隊(duì)列更新為 setTImeout 后的結(jié)果。 (代碼 1589 -1598 行)

7.和屬性有關(guān)擴(kuò)展 (代碼 1609 - 1988 行)

從這里開始,需要了解一個(gè)函數(shù)jQuery.access。對于 attr ,css 之類的函數(shù),如果需要返回值,只返回第一個(gè)元素的值,如果是設(shè)置值,則設(shè)置每個(gè)元素的值。這個(gè)神奇的效果就是 jQuery.access 搞定的。

jQuery.access代碼在 794 - 819 行

jQuery大部分函數(shù)都是依賴 jQuery.access 實(shí)現(xiàn)的,比如有一個(gè)函數(shù) XX,對用戶而言,調(diào)用的是 jQuery.fn.XX, 而這個(gè)函數(shù)需要對多個(gè)元素(jQuery數(shù)組內(nèi)的所有的節(jié)點(diǎn)) 操作,或者對1個(gè)元素操作, 通過 jQuery.access 轉(zhuǎn)換(不一定都是),最后只寫對1個(gè)元素的操作。這1個(gè)元素的操作往往是 jQuery.XX 函數(shù),因此,我們往往能看到即存在 jQuery.XX, 又存在 jQuery.fn.XX, 而其實(shí) jQuery.fn.XX 都是依靠 jQuery.XX 的,或者說jQuery.XX是底層函數(shù), jQuery.fn.XX 是方便用戶的工具 。

jQuery.fn.attr 這個(gè)函數(shù)(代碼 1632 - 1634 行) 只有1句話,真正的實(shí)現(xiàn)是  jQuery.attr (代碼 1880 - 1988)

又是一個(gè)大于100行的函數(shù)

attr: function( elem, name, value, pass ) {
// 檢查是否為 nodeType 為 Element
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) {
return undefined;
}

// 如果這個(gè)屬性需要特殊對待。 height/width/left 等屬性需特殊計(jì)算
if ( pass && name in jQuery.attrFn ) {
return jQuery(elem)[name](value);
}

// 檢查是否為 XML 還 HTML
var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
// Whether we are setting (or getting)
set = value !== undefined;

// 修正名字, 比如 float 改 cssFloat
name = notxml && jQuery.props[ name ] || name;

// 只有在節(jié)點(diǎn)的時(shí)候執(zhí)行。
if ( elem.nodeType === 1 ) {
// 在 IE7- 下, href src 屬性直接獲取會返回絕對位置,而不是真實(shí)的位置字符串,
// 要獲得它們的真實(shí)值,需要 elem.getAttribute("href", 2);
var special = rspecialurl.test( name );

// Safari 誤報(bào)默認(rèn)選項(xiàng)。通過獲取父元素的已選擇索引來修復(fù)。
if ( name === "selected" && !jQuery.support.optSelected ) {
var parent = elem.parentNode;
if ( parent ) {
parent.selectedIndex;

// 對 optgroups ,同理
if ( parent.parentNode ) {
parent.parentNode.selectedIndex;
}
}
}

// 檢查屬性是否存在, 有些時(shí)候 name in elem 會失敗,所以多次測試。
if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) {

// 如果設(shè)置屬性
if ( set ) {
// 在IE, 不能設(shè)置屬性 type 。
if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {
jQuery.error(
"type property can't be changed" );
}

// 如果 value === null, 表示移除屬性
if ( value === null ) {
if ( elem.nodeType === 1 ) {
elem.removeAttribute( name );
}

}
else {

// 一切屬性設(shè)置就是1句話。。。
elem[ name ] = value;
}
}

// 表單索引元素獲取需要 getAttributeNode( name ).nodeValue
if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
return elem.getAttributeNode( name ).nodeValue;
}

// elem.tabIndex 特殊處理
if ( name === "tabIndex" ) {
var attributeNode = elem.getAttributeNode( "tabIndex" );

return attributeNode && attributeNode.specified ?
attributeNode.value :
rfocusable.test( elem.nodeName )
|| rclickable.test( elem.nodeName ) && elem.href ?
0 :
undefined;
}

return elem[ name ];
}

// 處理 style 屬性
if ( !jQuery.support.style && notxml && name === "style" ) {
if ( set ) {
elem.style.cssText
= "" + value;
}

return elem.style.cssText;
}

if ( set ) {
// 這里除了 IE, 其它屬性使用標(biāo)準(zhǔn) setAttribute
elem.setAttribute( name, "" + value );
}

// 如果屬性不存在,返回 undefined, 而不是 null 或 "" 之類的。
if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) {
return undefined;
}

// 見上
var attr = !jQuery.support.hrefNormalized && notxml && special ?
// Some attributes require a special call on IE
elem.getAttribute( name, 2 ) :
elem.getAttribute( name );

// 同上
return attr === null ? undefined : attr;
}
// 如果不是 DOM 元素,檢查處理。
if ( set ) {
elem[ name ]
= value;
}
return elem[ name ];
}

windowData

8.和事件有關(guān)擴(kuò)展 (代碼 1993 - 3175 行)

   8.1 事件

      平時(shí)我們都是調(diào)用 click(func) 之類的函數(shù), 而其實(shí)這些都是工具函數(shù),真正和事件掛鉤的函數(shù)是

  jQuery.fn.bind - 調(diào)用 jQuery.event.add

 jQuery.fn.unbind - 調(diào)用 jQuery.event.remove

 jQuery.fn.trigger - 調(diào)用 jQuery.event.trigger

 jQuery.fn.one - 調(diào)用 jQuery.fn.bind,Query.fn.unbind

要想知道jQuery的事件原理,必須讀 jQuery.event.add (代碼 2012 - 2155  行)

add: function( elem, types, handler, data ) {

// 只對節(jié)點(diǎn)操作。
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}

// IE 無法傳遞 window,而是復(fù)制這個(gè)對象 。
if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
elem
= window;
}

// 如果 handler === false, 也就是說就是阻止某事件,
// 這樣只要 bind("evt", false); 就是阻止此事件。
if ( handler === false ) {
handler
= returnFalse;
}
else if ( !handler ) {
return;
}

// handleObjIn 是內(nèi)部處理句柄, handleObj 是直接使用的處理句柄。
var handleObjIn, handleObj;

if ( handler.handler ) {
handleObjIn
= handler;
handler
= handleObjIn.handler;
}

// 為函數(shù)生成唯一的 guid 。具體下面介紹。
if ( !handler.guid ) {
handler.guid
= jQuery.guid++;
}

// 獲取一個(gè)節(jié)點(diǎn)的數(shù)據(jù)。
var elemData = jQuery.data( elem );

// 如果沒有數(shù)據(jù),則直接返回。
if ( !elemData ) {
return;
}

// 避免和原生的js對象混淆。
var eventKey = elem.nodeType ? "events" : "__events__",

// 這里就是關(guān)鍵。
// elemData 是存儲數(shù)據(jù)的位置, 而 elemData[ eventKey ] 就是存儲當(dāng)前事件的對象。 elemData.handle 就是當(dāng)前綁定的所有函數(shù)數(shù)組。
// 也就是說,當(dāng)我們綁定一個(gè)函數(shù)時(shí),會往 elemData.handle 放這個(gè)函數(shù),然后事件觸發(fā)時(shí),會遍歷 elemData.handle 中函數(shù)然后去執(zhí)行。
// 肯能有人會問,為什么這么做,因?yàn)樵腄OM內(nèi)部也有一個(gè) 函數(shù)數(shù)組,事件觸發(fā)后會執(zhí)行全部函數(shù)。答案還是 兼容。
// 標(biāo)準(zhǔn)瀏覽器使用 addEventListener
// IE 使用 attachEvent
// 而這2者還是有差距的。因?yàn)?addEventListener 執(zhí)行函數(shù)的順序即添加函數(shù)的順序,然而 attachEvent 執(zhí)行函數(shù)的順序和添加的順序是相反的。
// jQuery 使用自定義的 handler 數(shù)組,好處有:
// 因?yàn)樽詈髢H綁定一次原生事件,事件觸發(fā)后,手動執(zhí)行 數(shù)組中的函數(shù)。這樣保證兼容。
// 同時(shí)也可以知道到底綁定了什么函數(shù),可以方便 trigger 函數(shù)的完成。

events
= elemData[ eventKey ],
eventHandle
= elemData.handle;

// 一些功能。。
if ( typeof events === "function" ) {
eventHandle
= events.handle;
events
= events.events;

}
else if ( !events ) {
if ( !elem.nodeType ) {
elemData[ eventKey ]
= elemData = function(){};
}

elemData.events
= events = {};
}

// 如果是第一次執(zhí)行,需創(chuàng)建 eventHandle
if ( !eventHandle ) {

// eventHandle 就是真正綁定到原生事件的那個(gè)函數(shù),這個(gè)函數(shù)用來執(zhí)行events.hadlers 用。
elemData.handle = eventHandle = function() {
// Handle the second event of a trigger and when
// an event is called after a page has unloaded
return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
jQuery.event.handle.apply( eventHandle.elem, arguments ) :
undefined;
};
}

// 綁定函數(shù)和原生,這樣可以保證函數(shù)可執(zhí)行為目前作用域。
eventHandle.elem = elem;

// 處理 jQuery(...).bind("mouseover mouseout", fn);
types = types.split(" ");

var type, i = 0, namespaces;

while ( (type = types[ i++ ]) ) {
handleObj
= handleObjIn ?
jQuery.extend({}, handleObjIn) :
{ handler: handler, data: data };

//

// 綁定 type guid
handleObj.type = type;
if ( !handleObj.guid ) {
handleObj.guid
= handler.guid;
}

// 獲取當(dāng)前的函數(shù)數(shù)組。
var handlers = events[ type ],
special
= jQuery.event.special[ type ] || {};

// 如果第一次,則創(chuàng)建這個(gè)數(shù)組。
if ( !handlers ) {
handlers
= events[ type ] = [];

// 特殊事件要執(zhí)行 setup 而不是標(biāo)準(zhǔn) addEventListener。
// 此行用來支持自定義的事件。
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// 標(biāo)準(zhǔn)事件。 這里綁定的為 eventHandle
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle,
false );

}
else if ( elem.attachEvent ) {
elem.attachEvent(
"on" + type, eventHandle );
}
}
}

// 自定義事件,執(zhí)行 add
if ( special.add ) {
special.add.call( elem, handleObj );

if ( !handleObj.handler.guid ) {
handleObj.handler.guid
= handler.guid;
}
}

// 不管是不是首次,都放入目前綁定的函數(shù)。
handlers.push( handleObj );

// 為實(shí)現(xiàn) trigger 。
jQuery.event.global[ type ] = true;
}

// 讓IE下可以正?;厥?elem 內(nèi)存。
elem = null;
},

8.2 事件對象

    框架的義務(wù)當(dāng)然也包括 事件參數(shù)的修復(fù)。jQuery 是自定義事件對象, 這個(gè)對象模擬真實(shí)事件對象。

    根據(jù)上文可以知道,真正綁定事件的是一個(gè)函數(shù),這個(gè)函數(shù)執(zhí)行時(shí)會先 生成自定義事件對象, 然后把此對象作為參數(shù)調(diào)用所有的 handler 。

     jQuery 自定義事件是 jQuery.Event 。 (代碼  2583-2610 行)

jQuery.Event = function( src ) {
// 支持 沒有 new jQuery.Event
if ( !this.preventDefault ) {
return new jQuery.Event( src );
}

//

}
這個(gè)函數(shù)做的就是模擬真實(shí)的事件對象。

此外,還要配合 jQuery.event.fix 使用。 (2470 - 2527行)

8.3 特殊(自定義)事件

特殊事件都定義在 jQuery.event.special 。  ( 代碼 2537 - 2567 行 )

默認(rèn)有  ready live beforeunload

一個(gè)特殊事件是jQuery內(nèi)部特別處理的事件,它們可自定義這個(gè)事件如何綁定、添加、刪除或觸發(fā)。

8.4 觸發(fā)事件

 代碼 2292 - 2403 行,目的就是為了模擬觸發(fā)某事件。這個(gè)函數(shù)支持模擬冒泡。

參考  http://www.cnblogs.com/rooney/archive/2008/12/03/1346449.html

9.內(nèi)部的Sizzle CSS Selector Engine (代碼 3183 - 4518 行)

  由于專門解釋選擇器的文章比較多,這里不多說了。

 參考 http://www.cnblogs.com/rooney/archive/2008/12/02/1346135.html

http://www.cnblogs.com/rubylouvre/archive/2009/11/23/1607917.html

10.和節(jié)點(diǎn)有關(guān)擴(kuò)展 (代碼 4520 - 5492 行)

   和節(jié)點(diǎn)有關(guān)的函數(shù)如: parent  next 等這些查找n個(gè)節(jié)點(diǎn)的工具。

  這些函數(shù)都依靠 jQuery.fn.nth() 通過 關(guān)系找到下個(gè)節(jié)點(diǎn),如果這個(gè)節(jié)點(diǎn)是 Element, 則返回,否則繼續(xù)找 

  由于這些函數(shù)都是比較易懂的,這里就不解釋了。

   一些HACK技巧強(qiáng)調(diào)下:

10.1 clone:  (代碼  5010 - 5037 行)

   jQuery 1.5 的clone 和 Mootools 的一樣,采用 cloneFixAttributes

   (代碼 5196 - 5225 行)

  cloneCopyEvent - 不是復(fù)制 data, 而是依據(jù) data 重執(zhí)行 bind

  cloneFixAttributes - 先 clearAttributes ,然后 mergeAttributes ( IE 專用) 這樣可以保證屬性正確拷貝。

10.2 jQuery.buildFragment (代碼 5276 - 5308 行 )

  這個(gè)函數(shù)用來按 HTML 返回節(jié)點(diǎn), 就是 $("復(fù)雜 html ")   所使用的。

  這里用到不常見的 document.createDocumentFragment();

10.3 evalScript (代碼 5478 - 5492  行)

   如果是 <script> 則執(zhí)行  jQuery.globalEval ( 全局執(zhí)行)

  為什么不直接把 <script> 放入head ? 因?yàn)?單個(gè) <script> 肯能導(dǎo)致泄漏。

10.4 clean (代碼 5340 -5433 行)

  刪除元素內(nèi)容子節(jié)點(diǎn)。

  參考 http://www.cnblogs.com/70buluo/archive/2009/06/03/1495040.html

參考 http://www.cnblogs.com/rooney/archive/2008/12/02/1346135.html

11. 和樣式有關(guān)擴(kuò)展 (代碼 5497 - 5825 行)

 獲取元素的css屬性確實(shí)是很郁悶的事。jQuery 首先把一些屬性單獨(dú)處理, 其余的使用 style[ name ] || ( IE ? getComputedStyle( elem, null).getProperty( name ) : elem.currentStyle [name] 的方式獲取,并稍微做點(diǎn)兼容處理。

  具體可以參考 http://www.cnblogs.com/rubylouvre/archive/2009/09/05/1559883.html

 http://www.cnblogs.com/rubylouvre/archive/2009/11/21/1607255.html

12.和ajax有關(guān)擴(kuò)展 (代碼 5830 - 7172 行)

 jQuery 1.5 重寫了 ajax 模塊。

  jQuery的 ajax其實(shí)也是使用一個(gè)模擬機(jī)制,而不是基于元素的 onreadystatechange

 也就是說, jQuery自己有個(gè)函數(shù), 每隔13ms 判斷 readystate是否 改了。

 參考 http://www.cnblogs.com/qleelulu/archive/2008/04/21/1163021.html

13. 和效果有關(guān)擴(kuò)展 (代碼 7176 - 7696 行)

  參考 http://www.cnblogs.com/rooney/archive/2008/12/03/1346475.html

 附加說明下特效轉(zhuǎn)換,

說到特效,很多人都知道這是依靠 setTimeout 完成的。但如何實(shí)現(xiàn)?

假設(shè)運(yùn)動是 勻速的。從 x = x1 開始運(yùn)動, 在 dt 中勻速運(yùn)動到 x =x2 的位置。

而因?yàn)?需要在 dt 內(nèi)把 x = x1 -> x2, 為了方便計(jì)算,特引入一個(gè) delta, 滿足  當(dāng)前的 x = x1 + (x2 - x1) * delta 。

所以整個(gè)動畫開始的時(shí)候 delta=0, 結(jié)束的時(shí)候則 dalta=1。這樣,無論多大的 x1, x2 ,特效的計(jì)算都變?yōu)?delta 的計(jì)算。

delta 隨時(shí)間變化,得到:

delta = f(t)  (0 < t < dt)   f 是一個(gè)映射。

每畫一幀的時(shí)候 , t 加1, 根據(jù) f 重新算 delta 和 x 。

假如我們需要一秒顯示 fps 幀, 那就是說每1000/fps 毫秒 顯示一次, 也就說 每1000/fps毫秒就顯示一幀,即 setTimeout (畫幀, 1000/fps)。

總結(jié)下: 輸入是 fps, x1, x2, dt  則代碼:

var t = 0, f = 某個(gè)變換;

setInterval(
function(){

var delta = f(t);

var x = x1 + (x2 - x1) * dalta;

// 更新顯示 x

t
++;

},
1000 / fps);

然后介紹 f 是什么, f 輸入是時(shí)間,輸出 delta。f(0) = 0,  f(dt) = 1。

在任一時(shí)刻: delta = (x - x1) / (x2 - x1)

當(dāng) x = 0 -> x

    t = 0 -> dt

根據(jù)微分理解:  f 是 x 方程的關(guān)于 t 的導(dǎo)函數(shù)。

當(dāng) x = k * t 為勻速運(yùn)動,這里的k = (x2 - x1) / dt

f = f|t = x' = k;

當(dāng) x = k * t 是拋物線,

f = x' = 2 * k * t;

一般情況, 使用 sin 函數(shù)變換柔和點(diǎn),所以jquery默認(rèn)使用sin變換,所以變換函數(shù)是

x = sin( t - 3π/2)   ( 最低點(diǎn) )

f = x' = -(cos( πt ) - 1)  / 2

(代碼  7477 行)

14.和定位有關(guān)擴(kuò)展 (代碼 7700 - 8065 行)

   jQuery.offset 用于管理定位,其它都是工具代碼。

jQuery.offset.initialize  測試瀏覽器的定位法則。

jQuery.offse.bodyOffset  獲取 body 的定位。 因?yàn)檫@個(gè)定位和其它的不同,所有單獨(dú)測試。

jQuery.fn.offset  這是核心定位函數(shù), 返回絕對位置,新瀏覽器使用 getBoundingClientRect ,否則自己計(jì)算。

自己計(jì)算的方法就是遍歷父元素,把相對位置相加,返回的就是和父元素的相對位置,那和body相對位置就是絕對位置。

參考 http://www.cnblogs.com/xuld/archive/2011/02/13/1953907.html

jQuery.fn.position  jQuery.fn.position 返回和 style.left 一樣。計(jì)算方法就是先 算 offset 和父節(jié)點(diǎn)(offsetParent) offset, 那么就可以得到偏移。

15. 總結(jié)

  分析源碼的時(shí)候可以對照代碼理解。jQuery雖然復(fù)雜但代碼還是好讀的。解讀源碼只要是為了更好地使用,所以知道源碼后,就自然知道為什么jQuery可以做這么多事。

但jQuery始終不是唯一的框架,感嘆它的設(shè)計(jì)同時(shí),還應(yīng)該看一下其它性格的框架,比如 Mootools 。

相關(guān)文章

  • js(jQuery)獲取時(shí)間的方法及常用時(shí)間類搜集

    js(jQuery)獲取時(shí)間的方法及常用時(shí)間類搜集

    獲取時(shí)間的方法及常用時(shí)間類都是大家經(jīng)常使用的,在本文為大家整理了一些,個(gè)人感覺還比較全,感興趣的朋友可以收集下
    2013-10-10
  • jquery點(diǎn)擊切換背景色的簡單實(shí)例

    jquery點(diǎn)擊切換背景色的簡單實(shí)例

    下面小編就為大家?guī)硪黄猨query點(diǎn)擊切換背景色的簡單實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-08-08
  • jquery.zclip輕量級復(fù)制失效問題

    jquery.zclip輕量級復(fù)制失效問題

    本文主要介紹了解決jquery.zclip輕量級復(fù)制失效問題的工作原理及方法。具有一定的參考價(jià)值,下面跟著小編一起來看下吧
    2017-01-01
  • jquery實(shí)現(xiàn)更改表格行順序示例

    jquery實(shí)現(xiàn)更改表格行順序示例

    本文主要介紹了jquery實(shí)現(xiàn)更改表格行順序示例,大家參考使用吧
    2014-04-04
  • jQuery 絕對入門

    jQuery 絕對入門

    對于想學(xué)習(xí)jquery 的朋友可以看下這樣的入門級文章。
    2009-04-04
  • jquery動態(tài)添加帶有樣式的HTML標(biāo)簽元素方法

    jquery動態(tài)添加帶有樣式的HTML標(biāo)簽元素方法

    下面小編就為大家分享一篇jquery動態(tài)添加帶有樣式的HTML標(biāo)簽元素方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • jQuery的事件預(yù)綁定

    jQuery的事件預(yù)綁定

    這篇文章主要介紹了jQuery的事件預(yù)綁定的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-12-12
  • jQuery獲取樣式中的背景顏色屬性值/顏色值

    jQuery獲取樣式中的背景顏色屬性值/顏色值

    天使用jQuery獲取樣式中的background-color的值時(shí)發(fā)現(xiàn)在獲取到的顏色值在IE中與Chrome、Firefox顯示的格式不一樣,IE中是以HEX格式顯示#ffff00,而Chrome、Firefox中則是以GRB格式顯示rgb(255,0,0),由于需要將顏色值存儲到數(shù)據(jù)庫中,所以想讓顏色值的格式統(tǒng)一下(其實(shí)不統(tǒng)一也是可以存的)。搜索了一下,從國外的一個(gè)網(wǎng)站上得到一段代碼
    2012-12-12
  • 實(shí)現(xiàn)easyui的datagrid導(dǎo)出為excel的示例代碼

    實(shí)現(xiàn)easyui的datagrid導(dǎo)出為excel的示例代碼

    下面小編就為大家?guī)硪黄獙?shí)現(xiàn)easyui的datagrid導(dǎo)出為excel的示例代碼。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-11-11
  • 基于jquery tab切換(防止頁面刷新)

    基于jquery tab切換(防止頁面刷新)

    tab切換,是一個(gè)很常見的效果,今天在項(xiàng)目中遇到這樣一個(gè)問題。就是切換后,頁面刷新,又重新定位到第一個(gè)上了,很是郁悶
    2012-05-05

最新評論