jquery3.0原始碼解讀(三)Selector
前置知識
- 正則表示式
- css選擇器
- DOM
- call
程式碼概況
第一節將jQuery初始化的時候,我們只是簡單講了下jQuery的構造方式,並沒有分析jQuery物件到底是如何具體構造出來的。
使用過jquery的同學一定知道,jquery的一個最大的用的最多的特性就是用來選擇頁面上的元素,這個真是太方便,太強大了。換句話說,構造jquery物件的過程,就是選擇器的實現過程。下面,我們來分析選擇器的實現(其實是jquery物件的構造過程)。
開啟/src/selector.js,程式碼如下:
define( [ "./selector-sizzle" ], function() {} );
直接指向selector-sizzle,那我們接著開啟/src/selector-sizzle.js,程式碼如下:
define( [
"./core",
"../external/sizzle/dist/sizzle"
], function( jQuery, Sizzle ) {
"use strict";
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
// Deprecated
jQuery.expr[ ":" ] = jQuery.expr.pseudos;
jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
jQuery.text = Sizzle.getText;
jQuery.isXMLDoc = Sizzle.isXML;
jQuery.contains = Sizzle.contains;
jQuery.escapeSelector = Sizzle.escape;
} );
注意到jQuery.find = Sizzle;,這個Sizzle本身就是一個純javascript實現的css選擇器引擎。換句話說,就是css選擇器的功能,用js也能做到。光是用這個,就完成了jquery選擇器的大部分功能。
jQuery的find功能我們也經常使用,這裡其實就是直接使用了Sizzle引擎。
功能說明
jquery的選擇器大概有如下幾種功能用法(這裡又是大量的過載):
jQuery(selector[,context])
在context(作為待查詢的 DOM 元素集、文件或 jQuery 物件)中通過selector(用來查詢的字串)查詢所有匹配的元素jQuery(element)
把element(DOM元素)封裝成jQuery物件jQuery(elementArray)
把elementArray(DOM元素陣列)封裝成jQuery物件jQuery(Object)
把Object(任意物件)封裝成jQuery物件jQuery(jQueryObject)
相當於克隆了一個jQueryObject物件jQuery(html[,owerDocument])
使用html字串(用於動態建立DOM元素的HTML標記字串),在owerDocument(建立DOM元素所在的文件)動態建立由jQuery物件包裝的DOM元素jQuery()
建立空jquery物件jQuery(html,attributes)
使用html字串(用於動態建立DOM元素的HTML標記字串)動態建立由jQuery物件包裝的DOM元素,並設定attributes(用於附加到新建立元素上的屬性、事件和方法)jQuery(callback)
允許你繫結一個在DOM文件載入完成後執行的函式,$(document).ready()的簡寫。
原始碼分析
原始碼如下:
init = jQuery.fn.init = function( selector, context, root ) {
var match, elem;
if ( !selector ) {
return this;
}
root = root || rootjQuery;
if ( typeof selector === "string" ) {
if ( selector[ 0 ] === "<" &&
selector[ selector.length - 1 ] === ">" &&
selector.length >= 3 ) {
match = [ null, selector, null ];
} else {
match = rquickExpr.exec( selector );
}
if ( match && ( match[ 1 ] || !context ) ) {
if ( match[ 1 ] ) {
context = context instanceof jQuery ? context[ 0 ] : context;
jQuery.merge( this, jQuery.parseHTML(
match[ 1 ],
context && context.nodeType ? context.ownerDocument || context : document,
true
) );
if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
for ( match in context ) {
if ( jQuery.isFunction( this[ match ] ) ) {
this[ match ]( context[ match ] );
} else {
this.attr( match, context[ match ] );
}
}
}
return this;
} else {
elem = document.getElementById( match[ 2 ] );
if ( elem ) {
this[ 0 ] = elem;
this.length = 1;
}
return this;
}
} else if ( !context || context.jquery ) {
return ( context || root ).find( selector );
} else {
return this.constructor( context ).find( selector );
}
} else if ( selector.nodeType ) {
this[ 0 ] = selector;
this.length = 1;
return this;
} else if ( jQuery.isFunction( selector ) ) {
return root.ready !== undefined ?
root.ready( selector ) :
selector( jQuery );
}
return jQuery.makeArray( selector, this );
};
第一步:判斷selector是否為空,是的話,直接返回this,也就是空的jquery物件。用法7解決;
第二步:定義了root為rootjQuery,這裡的rootjQuery其實就是jQuery( document ),主要用於選擇器為空的時候,用rootjQuery上下文來代替空值,繼續下面的鏈式操作(關於鏈式操作,我們在下一節中講);
第三步:判斷selector是否為字串、是否為DOM型別、是否是一個function。字串先保留;如果是DOM型別的話,this[ 0 ] = selector;長度賦值1,用法2解決;如果是function的話,判斷document是否ready,如果ready,就執行function,用法9解決(關於ready的實現,見之前的文章);
第四步:如果selector為字串,通過正則判斷selector是不是html字串,如果不是,判斷有沒有context,有的話,使用context呼叫find方法(也就是sizzle),沒有就是用document為context呼叫find。用法1解決;
第五步:如果selector為html字串,這裡說明一下rquickExpr,這個是用來匹配HTML標記和ID表示式,匹配後的結果,也就是match,為[找到的匹配,HTML標記,ID]。判斷match[1]也就是HTML標記是否存在,如果不存在,直接通過match[ 2 ]也就是ID去取對應元素;
第六步:如果match[1]存在,jquery通過parseHTML(將html字串轉換為dom)和merge(把第二個陣列merge到第一個陣列)方法,將HTML標記轉化為由jQuery物件包裝的DOM元素,並返回,用法6解決;如果有attributes的話,新增屬性,用法8解決;
第七步:剩下的還有用法3,4,5,它們都會被jQuery.makeArray處理。大致的意思就是處理成jquery陣列,這裡的makeArray對外是將一個類陣列物件轉換為真正的陣列物件,對內有個過載,就是處理成jquery陣列物件。