jQuery源碼分析-04 選擇器-Sizzle-工作原理分析
更新時(shí)間:2011年11月14日 23:47:26 作者:
在分析Sizzle源碼之前,先整理一下選擇器的工作原理,先明確一些選擇器中用到的名詞,后邊閱讀時(shí)不會(huì)有歧義
作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com
聲明:本文為原創(chuàng)文章,如需轉(zhuǎn)載,請(qǐng)注明來(lái)源并保留原文鏈接。
在分析Sizzle源碼之前,先整理一下選擇器的工作原理
先明確一些選擇器中用到的名詞,后邊閱讀時(shí)不會(huì)有歧義:
選擇器表達(dá)式: "div > p"
塊表達(dá)式: "div" "p"
并列選擇器表達(dá)式: "div, p"
塊分割器: Sizzle中的chunker正則,對(duì)選擇器表達(dá)式從左向右分割出一個(gè)個(gè)塊表達(dá)式
查找器: 對(duì)塊表達(dá)式進(jìn)行查找,找到的DOM元素?cái)?shù)組叫候選集
過(guò)濾器: 對(duì)塊表達(dá)式和候選集進(jìn)行過(guò)濾
關(guān)系過(guò)濾器 對(duì)塊表達(dá)式之間的關(guān)系進(jìn)行過(guò)濾,共有四種關(guān)系:"+" 緊挨著的兄弟關(guān)系;">" 父子關(guān)系;"" 祖先關(guān)系;"~" 之后的所有兄弟關(guān)系
候選集: 查找器的結(jié)果,待過(guò)濾器進(jìn)行過(guò)濾
映射集: 候選集的副本,過(guò)濾器和關(guān)系過(guò)濾器對(duì)映射集進(jìn)行過(guò)濾
工作流程:
1. 使用塊分割器對(duì)選擇器表達(dá)式進(jìn)行分割,從左向右
如果遇到用逗號(hào)","分割的并列選擇器表達(dá)式,只分割至第一個(gè)逗號(hào)前邊的選擇器表達(dá)式1,將剩余部分記錄下來(lái)
2. 對(duì)最后一個(gè)塊表達(dá)式進(jìn)行查找Sizzle.find,結(jié)果放入候選集set,并將塊表達(dá)式中匹配的字符串部分刪除
查找器Sizzle.find從正則集Expr.match獲取對(duì)應(yīng)的正則表達(dá)式,對(duì)塊表達(dá)式進(jìn)行匹配,匹配成功則從查找函數(shù)集Expr.find獲取對(duì)應(yīng)的查找函數(shù)執(zhí)行
查找順序定義在Expr.order中,依次是:ID CLASS NAME TAG,查找時(shí)CLASS需要瀏覽器支持getElementsByClassName
Expr.match中設(shè)定了ID CLASS NAME ATTR TAG CHILD POS PSEUDO的正則匹配表達(dá)式
3. 如果最后一個(gè)塊表達(dá)式不為空(字符串),過(guò)濾器Sizzle.filter對(duì)set進(jìn)行過(guò)濾
過(guò)濾器Sizzle.filter僅對(duì)單個(gè)塊表達(dá)式起作用,僅對(duì)候選集set中的元素起作用,檢查候選集set中的元素滿足剩余的塊表達(dá)式
在過(guò)濾器Sizzle.filter的過(guò)濾過(guò)程中,不符合條件的被設(shè)置為false,符合條件的不做修改
過(guò)濾時(shí)從正則集Expr.leftMatch獲取對(duì)應(yīng)的正則表達(dá)式,對(duì)塊表達(dá)式進(jìn)行匹配,匹配成功則從Expr.filter獲取對(duì)應(yīng)的過(guò)濾函數(shù)執(zhí)行
Expr.leftMatch定義了與Expr.match同樣數(shù)量的正則表達(dá)式:ID CLASS NAME ATTR TAG CHILD POS PSEUDO
過(guò)濾函數(shù)集Expr.filter定義了PSEUDO CHILD ID TAG CLASS ATTR POS的過(guò)濾函數(shù)
過(guò)濾器Sizzle.filter進(jìn)行過(guò)濾之前,會(huì)先調(diào)用預(yù)過(guò)濾器Expr.preFilter對(duì)過(guò)濾所需的參數(shù)進(jìn)行修正,但是CLASS是個(gè)例外
在CLASS進(jìn)行預(yù)過(guò)濾時(shí)做了優(yōu)化,直接將匹配class的元素作為候選集返回,縮小過(guò)濾范圍,縮小候選集范圍
將以上查找和過(guò)濾得到候選集set復(fù)制,放入映射集checkSet,后邊的過(guò)濾操作在checkSet上進(jìn)行
對(duì)最后一個(gè)塊表達(dá)式的查找和過(guò)濾到這里結(jié)束,得到一個(gè)候選集set和映射集checkSet
4. 在映射集checkSet上將剩余的塊表達(dá)式從右向左進(jìn)行過(guò)濾,根據(jù)與前一個(gè)塊表達(dá)式的關(guān)系,從關(guān)系過(guò)濾器集Expr.relative中獲取對(duì)應(yīng)的函數(shù)執(zhí)行關(guān)系過(guò)濾
在關(guān)系過(guò)濾器Expr.relative的過(guò)濾過(guò)程中,不符合條件的被設(shè)置為false,符合條件的則被設(shè)置為父元素、祖先元素、兄長(zhǎng)元素
元素之間的關(guān)系共有四種:"+" 緊挨著的兄弟關(guān)系;">" 父子關(guān)系;"" 祖先關(guān)系;"~" 之后的所有兄弟關(guān)系
在關(guān)系過(guò)濾器Expr.relative的過(guò)濾過(guò)程中,如果遇到塊表達(dá)式是標(biāo)簽TAG的情況,則直接比較標(biāo)簽類(lèi)型nodeName是否相等
如果不是標(biāo)簽TAG的情況,則會(huì)調(diào)用過(guò)濾器Sizzle.filter進(jìn)行過(guò)濾,過(guò)濾過(guò)程見(jiàn)第3步
從右向左過(guò)濾,直到所有塊表達(dá)式全部過(guò)濾完
5. 根據(jù)過(guò)濾后的映射集checkSet,從候選集set中挑選最終的結(jié)果集,在映射集checkSet中
如果是null、false,將被過(guò)濾
如果不是Element(nodeType===1),將被過(guò)濾
如果上下文不是Document而是某個(gè)Element,不是Element的子元素的,將被過(guò)濾
6. 如果存在并列表達(dá)式,重復(fù)1~5,并將得到的最終結(jié)果集合并、排序、去重
如果僅有一個(gè)選擇器表達(dá)式,沒(méi)有并列選擇器表達(dá)式,不需要排序
以下過(guò)程不屬于Sizzle,屬于jQuery對(duì)Sizzle的擴(kuò)展
7. 如果存在多個(gè)上下文,對(duì)每個(gè)上下文重復(fù)1~6
多個(gè)上下文例子:$('div').find('div > p'),$('div')可能找到多個(gè)div
其實(shí)第7步是jQuery選擇器的入口,從第7步去調(diào)用1~6,調(diào)用時(shí)傳入一個(gè)空的jQuery對(duì)象作為結(jié)果集
默認(rèn)以document為上下文:(context || rootjQuery).find( selector )
8. 將從多個(gè)上下文找到的結(jié)果集合并、去重,返回結(jié)果集
done!
聲明:本文為原創(chuàng)文章,如需轉(zhuǎn)載,請(qǐng)注明來(lái)源并保留原文鏈接。
在分析Sizzle源碼之前,先整理一下選擇器的工作原理
先明確一些選擇器中用到的名詞,后邊閱讀時(shí)不會(huì)有歧義:
選擇器表達(dá)式: "div > p"
塊表達(dá)式: "div" "p"
并列選擇器表達(dá)式: "div, p"
塊分割器: Sizzle中的chunker正則,對(duì)選擇器表達(dá)式從左向右分割出一個(gè)個(gè)塊表達(dá)式
查找器: 對(duì)塊表達(dá)式進(jìn)行查找,找到的DOM元素?cái)?shù)組叫候選集
過(guò)濾器: 對(duì)塊表達(dá)式和候選集進(jìn)行過(guò)濾
關(guān)系過(guò)濾器 對(duì)塊表達(dá)式之間的關(guān)系進(jìn)行過(guò)濾,共有四種關(guān)系:"+" 緊挨著的兄弟關(guān)系;">" 父子關(guān)系;"" 祖先關(guān)系;"~" 之后的所有兄弟關(guān)系
候選集: 查找器的結(jié)果,待過(guò)濾器進(jìn)行過(guò)濾
映射集: 候選集的副本,過(guò)濾器和關(guān)系過(guò)濾器對(duì)映射集進(jìn)行過(guò)濾
工作流程:
1. 使用塊分割器對(duì)選擇器表達(dá)式進(jìn)行分割,從左向右
如果遇到用逗號(hào)","分割的并列選擇器表達(dá)式,只分割至第一個(gè)逗號(hào)前邊的選擇器表達(dá)式1,將剩余部分記錄下來(lái)
2. 對(duì)最后一個(gè)塊表達(dá)式進(jìn)行查找Sizzle.find,結(jié)果放入候選集set,并將塊表達(dá)式中匹配的字符串部分刪除
查找器Sizzle.find從正則集Expr.match獲取對(duì)應(yīng)的正則表達(dá)式,對(duì)塊表達(dá)式進(jìn)行匹配,匹配成功則從查找函數(shù)集Expr.find獲取對(duì)應(yīng)的查找函數(shù)執(zhí)行
查找順序定義在Expr.order中,依次是:ID CLASS NAME TAG,查找時(shí)CLASS需要瀏覽器支持getElementsByClassName
Expr.match中設(shè)定了ID CLASS NAME ATTR TAG CHILD POS PSEUDO的正則匹配表達(dá)式
3. 如果最后一個(gè)塊表達(dá)式不為空(字符串),過(guò)濾器Sizzle.filter對(duì)set進(jìn)行過(guò)濾
過(guò)濾器Sizzle.filter僅對(duì)單個(gè)塊表達(dá)式起作用,僅對(duì)候選集set中的元素起作用,檢查候選集set中的元素滿足剩余的塊表達(dá)式
在過(guò)濾器Sizzle.filter的過(guò)濾過(guò)程中,不符合條件的被設(shè)置為false,符合條件的不做修改
過(guò)濾時(shí)從正則集Expr.leftMatch獲取對(duì)應(yīng)的正則表達(dá)式,對(duì)塊表達(dá)式進(jìn)行匹配,匹配成功則從Expr.filter獲取對(duì)應(yīng)的過(guò)濾函數(shù)執(zhí)行
Expr.leftMatch定義了與Expr.match同樣數(shù)量的正則表達(dá)式:ID CLASS NAME ATTR TAG CHILD POS PSEUDO
過(guò)濾函數(shù)集Expr.filter定義了PSEUDO CHILD ID TAG CLASS ATTR POS的過(guò)濾函數(shù)
過(guò)濾器Sizzle.filter進(jìn)行過(guò)濾之前,會(huì)先調(diào)用預(yù)過(guò)濾器Expr.preFilter對(duì)過(guò)濾所需的參數(shù)進(jìn)行修正,但是CLASS是個(gè)例外
在CLASS進(jìn)行預(yù)過(guò)濾時(shí)做了優(yōu)化,直接將匹配class的元素作為候選集返回,縮小過(guò)濾范圍,縮小候選集范圍
將以上查找和過(guò)濾得到候選集set復(fù)制,放入映射集checkSet,后邊的過(guò)濾操作在checkSet上進(jìn)行
對(duì)最后一個(gè)塊表達(dá)式的查找和過(guò)濾到這里結(jié)束,得到一個(gè)候選集set和映射集checkSet
4. 在映射集checkSet上將剩余的塊表達(dá)式從右向左進(jìn)行過(guò)濾,根據(jù)與前一個(gè)塊表達(dá)式的關(guān)系,從關(guān)系過(guò)濾器集Expr.relative中獲取對(duì)應(yīng)的函數(shù)執(zhí)行關(guān)系過(guò)濾
在關(guān)系過(guò)濾器Expr.relative的過(guò)濾過(guò)程中,不符合條件的被設(shè)置為false,符合條件的則被設(shè)置為父元素、祖先元素、兄長(zhǎng)元素
元素之間的關(guān)系共有四種:"+" 緊挨著的兄弟關(guān)系;">" 父子關(guān)系;"" 祖先關(guān)系;"~" 之后的所有兄弟關(guān)系
在關(guān)系過(guò)濾器Expr.relative的過(guò)濾過(guò)程中,如果遇到塊表達(dá)式是標(biāo)簽TAG的情況,則直接比較標(biāo)簽類(lèi)型nodeName是否相等
如果不是標(biāo)簽TAG的情況,則會(huì)調(diào)用過(guò)濾器Sizzle.filter進(jìn)行過(guò)濾,過(guò)濾過(guò)程見(jiàn)第3步
從右向左過(guò)濾,直到所有塊表達(dá)式全部過(guò)濾完
5. 根據(jù)過(guò)濾后的映射集checkSet,從候選集set中挑選最終的結(jié)果集,在映射集checkSet中
如果是null、false,將被過(guò)濾
如果不是Element(nodeType===1),將被過(guò)濾
如果上下文不是Document而是某個(gè)Element,不是Element的子元素的,將被過(guò)濾
6. 如果存在并列表達(dá)式,重復(fù)1~5,并將得到的最終結(jié)果集合并、排序、去重
如果僅有一個(gè)選擇器表達(dá)式,沒(méi)有并列選擇器表達(dá)式,不需要排序
以下過(guò)程不屬于Sizzle,屬于jQuery對(duì)Sizzle的擴(kuò)展
7. 如果存在多個(gè)上下文,對(duì)每個(gè)上下文重復(fù)1~6
多個(gè)上下文例子:$('div').find('div > p'),$('div')可能找到多個(gè)div
其實(shí)第7步是jQuery選擇器的入口,從第7步去調(diào)用1~6,調(diào)用時(shí)傳入一個(gè)空的jQuery對(duì)象作為結(jié)果集
默認(rèn)以document為上下文:(context || rootjQuery).find( selector )
8. 將從多個(gè)上下文找到的結(jié)果集合并、去重,返回結(jié)果集
done!
相關(guān)文章
jquery實(shí)現(xiàn)很酷的網(wǎng)頁(yè)頂部圖標(biāo)下拉菜單效果
這篇文章主要介紹了jquery實(shí)現(xiàn)很酷的網(wǎng)頁(yè)頂部圖標(biāo)下拉菜單效果,效果非常美觀大方,通過(guò)鼠標(biāo)hover事件及頁(yè)面元素的遍歷與樣式操作實(shí)現(xiàn)該功能,需要的朋友可以參考下2015-08-08
深入理解jquery自定義動(dòng)畫(huà)animate()
下面小編就為大家?guī)?lái)一篇深入理解jquery自定義動(dòng)畫(huà)animate()。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-05-05
基于JQuery的6個(gè)Tab選項(xiàng)卡插件
今天在修整博客側(cè)欄信息時(shí),利用到了Tab選項(xiàng)卡方式,因?yàn)閆Blog封裝的是JQuery庫(kù),所以很自然地就想到了IdTabs。2010-09-09
jQuery插件實(shí)現(xiàn)非常實(shí)用的tab欄切換功能【案例】
這篇文章主要介紹了jQuery插件實(shí)現(xiàn)非常實(shí)用的tab欄切換功能,涉及jQuery事件響應(yīng)及頁(yè)面元素屬性動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-02-02
jQuery輕松實(shí)現(xiàn)無(wú)縫輪播效果
這篇文章主要為大家詳細(xì)介紹了jQuery輕松實(shí)現(xiàn)無(wú)縫輪播效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
jquery實(shí)現(xiàn)的提示浮層跟隨鼠標(biāo)移動(dòng)
提示浮層跟隨鼠標(biāo)移動(dòng)(jquery版)2010-02-02
jquery.Jwin.js 基于jquery的彈出層插件代碼
測(cè)試頁(yè)面需要引用jquery的js文件 插件文件jquery.Jwin.js jquery.Jwin插件的使用參數(shù)都有詳細(xì)說(shuō)明2012-05-05
JQuery擴(kuò)展插件Validate 3通過(guò)參數(shù)設(shè)置錯(cuò)誤信息
最終顯示在頁(yè)面上的錯(cuò)誤分為兩種:第一種是默認(rèn)錯(cuò)誤信息,該信息已經(jīng)被定義在插件中了,可以手動(dòng)修改。2011-09-09

