zepto-selector.js簡單分析

zepto 的selector模塊是對jquery擴充選擇器(jquery-selector-extensions)的部分實現。好比這樣的選擇方法:$('div:first') 和 el.is(':visible')。
css

下面是原代碼,簡單的寫了一些註釋~node

;(function($){
  var zepto = $.zepto, oldQsa = zepto.qsa, oldMatches = zepto.matches
  /*
  *  檢察一個元素是否可見。除了要判斷display是不是none以外,還判斷了width和height是不是0,
  雙歎號是強制轉化成boolean類型
  */
  function visible(elem){
    elem = $(elem)
    return !!(elem.width() || elem.height()) && elem.css("display") !== "none"
  }

  // 實現的是jquey選擇器擴展的一部分
  // http://api.jquery.com/category/selectors/jquery-selector-extensions/
  //
  // 每個filter函數的參數都能接受當前值,全部考慮範圍內的節點和括號中的值
  // this就是當前被考慮的node. 函數返回的是node(s), null 或者是undefined
  //
  // 複雜的選擇器是不被支持的,好比下面的:
  //   li:has(label:contains("foo")) + li:has(label:contains("bar"))
  //   ul.inner:first > li
  var filters = $.expr[':'] = {
    visible:  function(){ if (visible(this)) return this },//可見
    hidden:   function(){ if (!visible(this)) return this },//不可見
    selected: function(){ if (this.selected) return this },//選中
    checked:  function(){ if (this.checked) return this },//勾選中
    parent:   function(){ return this.parentNode },//父節點
    first:    function(idx){ if (idx === 0) return this },//第一個元素
    last:     function(idx, nodes){ if (idx === nodes.length - 1) return this },//最後一個元素
    eq:       function(idx, _, value){ if (idx === value) return this },//相同的元素
    contains: function(idx, _, text){ if ($(this).text().indexOf(text) > -1) return this },//內容含有的元素
    has:      function(idx, _, sel){ if (zepto.qsa(this, sel).length) return this }//
  }

  var filterRe = new RegExp('(.*):(\\w+)(?:\\(([^)]+)\\))?$\\s*'),//一個強大的正則表達式用來分解選擇器的的,見下面
      childRe  = /^\s*>/,
      classTag = 'Zepto' + (+new Date())

  function process(sel, fn) {//分解選擇器爲三部分,第一部分是選擇器自己,第二部分是選擇器的值filter中的函數名稱,第三部分是參數
    //例如:(1)filterRe.exec(":eq(2)")
    //獲得的結果:[":eq(2)", "", "eq", "2"]
    //(2)filterRe.exec(":visible")
    //獲得的結果:[":visible", "", "visible", undefined]
    // quote the hash in `a[href^=#]` expression
    sel = sel.replace(/=#\]/g, '="#"]')
    var filter, arg, match = filterRe.exec(sel)
    if (match && match[2] in filters) {
      filter = filters[match[2]], arg = match[3]//filter爲filters中對應的函數
      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 = function(node, selector) {
    return process(selector, function(sel, filter, arg){
      try {
        var taggedParent
        if (!sel && filter) sel = '*'
        else if (childRe.test(sel))
          // support "> *" child queries by tagging the parent node with a
          // unique class and prepending that classname onto the selector
          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) }))
    })
  }

//
 //selector和function(sel,filter,arg){}傳到process中,
//處理完後,運行function(sel,filter,arg){},其中sel是selector通過強大正則以後的第二塊,filter是filters中對於的函數,arg是selector中的參數
  zepto.matches = function(node, selector){
    return process(selector, function(sel, filter, arg){
      return (!sel || oldMatches(node, sel)) &&
        (!filter || filter.call(node, null, arg) === node)
    })
  }
})(Zepto)
相關文章
相關標籤/搜索