jQuery選取器代碼詳解(四)——Expr.preFilter
Expr.preFilter是tokenize方法中對ATTR、CHILD、PSEUDO三種選取器進行預先處理的方法。具體如下:
Expr.preFilter : {ATTR : function(match) {/* * 完成如下任務: * 1、屬性名稱解碼 * 2、屬性值解碼 * 3、若判斷符為~=,則在屬性值兩邊加上空格 * 4、返回最終的mtach對象 * * match[1]表示屬性名稱, * match[1].replace(runescape, funescape):將屬性名稱中的十六進位數解碼成 * 單位元組unicode字元或雙位元組unicode字元(中文或其它需要兩個位元組表達的文字) * Regex的詳細說明,可以參看我的“詳解jQuery選取器Regex”文章 */match[1] = match[1].replace(runescape, funescape);/* * 將屬性值解碼 * match[4]:表示放在單引號或雙引號內的屬性值 * match[5]: 表示不用引號括起來的屬性值 */match[3] = (match[4] || match[5] || ).replace(runescape,funescape);/* * ~=的意思是單詞匹配,在W3C中對單詞的定義是以空白為不同單詞的分隔字元 * 故此處在match[3]兩邊加上空格後,可以利用indexOf,正確識別出該單詞是否存在 */if (match[2] === ~=) {match[3] = + match[3] + ;}/* * 返回有用的前四個元素結果 */return match.slice(0, 4);},CHILD : function(match) {/* * 完成如下幾項任務: * 1、把命令中child和of-type之前的字元變成小寫字元 * 2、對於nth開頭的選取器檢查括弧內的資料有效性 * 3、match[4]和match[5]分別存放xn+b中的x和b,x和b允許是負數 * 4、返回最終的match對象 * * match[1]:(only|first|last|nth|nth-last)中的一個 */match[1] = match[1].toLowerCase();/* * 對於nth-child、nth-of-type、nth-last-child、nth-last-of-type四種類型括弧內需設定有效資料 * 而其它則括弧內不允許有任何資料 */if (match[1].slice(0, 3) === nth) {/* * 若選取器括弧內沒有有效參數,則拋出異常 * 舉例:若選取器是nth或nth(abc)則屬於非法選取器 */if (!match[3]) {Sizzle.error(match[0]);}/* * 下面先以nth-child()為例介紹一下文法,以便更好的理解下面代碼的作用 * nth-child允許的幾種使用方式如下: * :nth-child(even) * :nth-child(odd) * :nth-child(3n) * :nth-child(+2n+1) * :nth-child(2n-1) * 下面代碼中賦值號左側的match[4]、match[5]用於分別記錄括弧內n前及n後的數值,包括加號或減號 * 對於:nth-child(even)和:nth-child(odd)來說,match[4]為空白, * 所以返回 2 * (match[3] === even || match[3] === odd)的計算結果 * 因為在js中true=1,false=0,所以(match[3] === even || match[3] === odd)等於1 * 因此,2 * (match[3] === even || match[3] === odd)的計算結果為2 * * 等號右側的“+”的作用是強制類型轉換,將之後的字串轉換成數實值型別 */match[4] = +(match[4] ? match[5] + (match[6] || 1): 2 * (match[3] === even || match[3] === odd));match[5] = +((match[7] + match[8]) || match[3] === odd);} else if (match[3]) {/* * 若非nth起頭的其它CHILD類型選取器帶有括弧說明,則拋出異常 * 這裡jQuery並沒有嚴格按照W3C的規則來判定,因為其允許:first-child()的這種形式存在 * 也就是對於jQuery來說:first-child()等同於:first-child,是合法選取器 */Sizzle.error(match[0]);}return match;},PSEUDO : function(match) {/* * 完成如下任務: * 1、擷取偽類中用引號括起來的值 * 2、對於非引號括起來的值,若存在偽類嵌套,則進一步解析確定當前偽類實際結束位置, * 擷取當前偽類的完整字串和值 * 3、返回match中的前三項的副本。 * * unquoted表示括弧內非引號括起來的值, * 以:eq(2)為例,unquoted=2 */var excess, unquoted = !match[5] && match[2];/* * 因為pseudo與child的匹配Regex有交集,所以,需要把屬於child的部分忽略掉 */if (matchExpr[CHILD].test(match[0])) {return null;}/* * 若括弧內的值使用引號(match[3])括起來的, * 則將除引號外的值(match[4])賦給match[2]。 * match[3]表示引號。 */if (match[3] && match[4] !== undefined) {match[2] = match[4];} else if (unquoted/* * rpseudo.test(unquoted):用來測試unquoted是否包含偽類, * 若包含偽類,則說明有可能存在偽類嵌套的可能性,需要進一步對unquoted進行解析 * 例如: :not(:eq(3)) */&& rpseudo.test(unquoted)&&/* * 擷取unquoted中連續有效地選取器最後一個字元所在位置 */(excess = tokenize(unquoted, true))&&/* * unquoted.indexOf(), unquoted.length - excess) * 從之前獲得的連續有效地選取器最後一個字元所在位置之後找到)所在位置, * 通常就在當前位置之後。 * 再減去unquoted.length,用來獲得match[0]中的有效完整的偽類字串最後位置, * 注意,此時excess是一個負值 * */(excess = unquoted.indexOf(), unquoted.length- excess)- unquoted.length)) {// 擷取有效完整偽類match[0]和偽類括弧內的資料match[2]match[0] = match[0].slice(0, excess);match[2] = unquoted.slice(0, excess);}// 返回match前三個元素的副本return match.slice(0, 3);}}
上一篇http://www.bkjia.com/kf/201502/377388.html