sizzle受歡迎的原因有以下幾點(diǎn):
1.幾乎支持大部分的css,還支持CSS3新的屬性,同時(shí)又很高效。
一般選擇器的匹配模式(包括老版本的jQuery),都是一個(gè)順序的思維方式:
在需要遞進(jìn)式匹配時(shí),比如$("div a") 這樣的匹配時(shí),執(zhí)行的操縱都是先匹配頁面中div然后再匹配它的節(jié)點(diǎn)下的a標(biāo)簽,之后返回結(jié)果。我們知道CSS的匹配規(guī)則是從右邊向左篩選,jQuery在Sizzle中延續(xù)了這樣的算法,先搜尋頁面中所有的a標(biāo)簽,在之后的操縱中再往后判定它的父節(jié)點(diǎn)(包括父節(jié)點(diǎn)以上)是否為div,一層一層往上過濾,最后返回該操縱序列。
sizzle只能說是大體如此,此外在1.8中引入了編譯的概念,大大提高了重復(fù)的選擇的效率。
瀏覽器渲染原理:
瀏覽器從下載文檔到顯示頁面的過程是個(gè)復(fù)雜的過程,這里包含了重繪和重排。各家瀏覽器引擎的工作原理略有差別,但也有一定規(guī)則。
簡單講,通常在文檔初次加載時(shí),瀏覽器引擎會(huì)解析HTML文檔來構(gòu)建DOM樹,之后根據(jù)DOM元素的幾何屬性構(gòu)建一棵用于渲染的樹。渲染樹的每個(gè)節(jié)點(diǎn)都有大小和邊距等屬性,類似于盒子模型(由于隱藏元素不需要顯示,渲染樹中并不包含DOM樹中隱藏的元素)。
當(dāng)渲染樹構(gòu)建完成后,瀏覽器就可以將元素放置到正確的位置了,再根據(jù)渲染樹節(jié)點(diǎn)的樣式屬性繪制出頁面。由于瀏覽器的流布局,對渲染樹的計(jì)算通常只需要遍歷一次就可以完成,所以我們知道瀏覽器最終會(huì)將HTML文檔(或者說頁面)解析成一棵DOM樹,如下代碼將會(huì)翻譯成以下的DOM:
<div id="text"> <p> <input type="text" /> </p> <div class="aaron"> <input type="checkbox" name="readme" /> <input type="checkbox" name="ttt" /> <input type="checkbox" name="aaa" /> <p>Sizzle</p> </div> </div>
如果想要操作到當(dāng)中那個(gè)checkbox,我們需要有一種表述方式,使得通過這個(gè)表達(dá)式讓瀏覽器知道我們是想要操作哪個(gè)DOM節(jié)點(diǎn)。
這個(gè)表述方式就是CSS選擇器,它是這樣表示的:
div > p + .aaron input[type="checkbox"]
表達(dá)的意思是:div底下的p的兄弟節(jié)點(diǎn),該節(jié)點(diǎn)的class為aaron ,并且其屬性type為checkbox。
常見的選擇器:
#test
表示id為test的DOM節(jié)點(diǎn).aaron
表示class為aaron的DOM節(jié)點(diǎn)input
表示節(jié)點(diǎn)名為input的DOM節(jié)點(diǎn)div > p
表示div底下的p的DOM節(jié)點(diǎn)div + p
表示div的兄弟DOM節(jié)點(diǎn)p
其實(shí)最終都是通過瀏覽器提供的接口實(shí)現(xiàn)的,由于低級瀏覽器并未提供這些高級點(diǎn)的接口,所以才有了Sizzle這個(gè)CSS選擇器引擎。Sizzle引擎提供的接口跟document.querySelectorAll是一樣的,其輸入是一串選擇器字符串,輸出則是一個(gè)符合這個(gè)選擇器規(guī)則的DOM節(jié)點(diǎn)列表,因此第一步驟是要分析這個(gè)輸入的選擇器。
通過sizzle與高級API獲取的結(jié)果是一致的:
$('div > div.aaron input[name=ttt]') document.querySelectorAll(' div > div.aaron input[name=ttt]')
這個(gè)是相對復(fù)雜的CSS的組合了,涉及到了幾種不同類型的選擇器,除去querySelectorAll這種高級API,我們是無法直接獲取到對應(yīng)的節(jié)點(diǎn)引用的,因?yàn)镾izzle要實(shí)現(xiàn)這種查找也是非常復(fù)雜的,這里面就要涉及一系列的概念。
1.拆分選擇器,把每一個(gè)選擇器組成能夠處理的最小化單元。
div.aaron
這行代碼原生的API不認(rèn)識,但是div與.aaron都是有API能直接獲取到的,所以拆分出后提供后面進(jìn)行關(guān)聯(lián)匹配篩選等等。這里sizzle就引入了詞法分析器與種子合集。
2.Sizzle也是遵循從右到左開始查找,但是不僅僅是這樣。
瀏覽器提供的查找接口,基本靠譜的就只有三個(gè):
Expr.find = { 'ID' : context.getElementById, 'CLASS' : context.getElementsByClassName, 'TAG' : context.getElementsByTagName }
所以我們開始第一查找,從右到左邊依次取出最小的單元選擇器,通過ID、CLASS.TAG去查找,如果能找到就放到結(jié)果集中,這樣第一時(shí)間定位到了最終的元素必須會(huì)存在的合集。
3.這樣只能找出可能存在的合集,但是沒有精確到具體的選擇器上,所以還需要一個(gè)篩選的過程,這個(gè)過程也是最復(fù)雜的。
Sizzle從1.8后引入的“編譯”的概念,用于提高性能。
請驗(yàn)證,完成請求
由于請求次數(shù)過多,請先驗(yàn)證,完成再次請求
打開微信掃碼自動(dòng)綁定
綁定后可得到
使用 Ctrl+D 可將課程添加到書簽
舉報(bào)