使用的正則: (.):(\w+)(?:\(([^)]+)\))?$\s
圖形化展示:
;(function($){
var zepto = $.zepto, oldQsa = zepto.qsa, oldMatches = zepto.matches
// 判斷元素是否可見
function visible(elem){
// 先將元素轉化成一個 zepto 對象,方便後面調用 zepto 方法
elem = $(elem)
// 通過判斷元素的寬高與 display 是否爲 display 來判斷元素是否可見
return !!(elem.width() || elem.height()) && elem.css("display") !== "none"
}
var filters = $.expr[':'] = {
// 匹配 el:visible 選擇器
visible: function(){ if (visible(this)) return this },
// 匹配 el:hidden 選擇器
hidden: function(){ if (!visible(this)) return this },
// 匹配 el:selected 選擇器
selected: function(){ if (this.selected) return this },
// 匹配 el:checked 選擇器
checked: function(){ if (this.checked) return this },
// 匹配 el:parent 選擇器
parent: function(){ return this.parentNode },
// 匹配 el:first 選擇器
first: function(idx){ if (idx === 0) return this },
// 匹配 el:last 選擇器
last: function(idx, nodes){ if (idx === nodes.length - 1) return this },
// 匹配 el:eq(index) 選擇器
eq: function(idx, _, value){ if (idx === value) return this },
// 匹配 el:contains(text)
contains: function(idx, _, text){ if ($(this).text().ivisiblendexOf(text) > -1) return this },
// 匹配 el:has(sel)
has: function(idx, _, sel){ if (zepto.qsa(this, sel).length) return this }
}
var filterRe = new RegExp('(.*):(\\w+)(?:\\(([^)]+)\\))?$\\s*'),
childRe = /^\s*>/,
classTag = 'Zepto' + (+new Date())
// 根據傳入的 sel 選擇器,分解出選擇器,僞類,僞類參數,根據選擇器選擇對應的 filter
function process(sel, fn) {
// 用於處理 a[href=#] 這一類寫法,正常應該是 a[href="#"] 這是爲了容錯
sel = sel.replace(/=#\]/g, '="#"]')
var filter, arg, match = filterRe.exec(sel)
// 如果是僞類,且僞類名存在於 filters 對象中,然後處理對應的值
if (match && match[2] in filters) {
filter = filters[match[2]], arg = match[3]
sel = match[1]
if (arg) {
var num = Number(arg)
if (isNaN(num)) arg = arg.replace(/^["']|["']$/g, '')
else arg = num
}
}
// 調用傳入的回調並返回結果
return fn(sel, filter, arg)
}
// 重寫 zepto.qsa 方法
zepto.qsa = function(node, selector) {
// 主要就是調用 process 方法,將主要邏輯放在回調中執行,和原方法並沒有太大的區別
return process(selector, function(sel, filter, arg){
try {
var taggedParent
if (!sel && filter) sel = '*'
else if (childRe.test(sel))
taggedParent = $(node).addClass(classTag), sel = '.'+classTag+' '+sel
var nodes = oldQsa(node, sel)
} catch(e) {
console.error('error performing selector: %o', selector)
throw e
} finally {
if (taggedParent) taggedParent.removeClass(classTag)
}
return !filter ? nodes :
zepto.uniq($.map(nodes, function(n, i){ return filter.call(n, i, nodes, arg) }))
})
}
// 重寫 zepto.matches 方法
zepto.matches = function(node, selector){
// 主要就是調用 process 方法,將主要邏輯放在回調中執行,和原方法沒有太大的區別
return process(selector, function(sel, filter, arg){
return (!sel || oldMatches(node, sel)) &&
(!filter || filter.call(node, null, arg) === node)
})
}
})(Zepto)