zepto 源碼分析1

核心

$() / zepto.init()

  • 相似 CSS 選擇器,選擇元素組成 zepto 對象集合
  • 將 HTML 字符串轉化成 zepto 對象集合
  • 根據給定標籤和屬性生成 zepto 對象集合
  • 給定函數,在頁面加載完成後觸發函數
zepto.init = function(selector, context) {
  var dom
  // 參數沒內容,則返回空集合
  if (!selector) return zepto.Z()
  else if (typeof selector == 'string') {
    selector = selector.trim()
    // 若是是 html 標籤,則生成 dom 元素
    // 先行檢查是否爲 < 開頭,提升正則檢測效率
    if (selector[0] == '<' && fragmentRE.test(selector))
      dom = zepto.fragment(selector, RegExp.$1, context), selector = null
    // 若是有 context,則生成 context 的對象集合,再檢索
    else if (context !== undefined) return $(context).find(selector)
    // 以 css 規則檢索元素
    else dom = zepto.qsa(document, selector)
  }
  // 若是傳參是函數,則在頁面加載完成時觸發執行 
  else if (isFunction(selector)) return $(document).ready(selector)
  // 若是給定的是 zepto 集合,直接返回
  else if (zepto.isZ(selector)) return selector
  else {
    // 是數組,則過濾 null 元素
    if (isArray(selector)) dom = compact(selector)
    // 是對象,則包在數組中
    else if (isObject(selector))
      dom = [selector], selector = null
    // If it's a html fragment, create nodes from it
    // 什麼狀況下邏輯會走到下面?此時 html fragment 是什麼??
    else if (fragmentRE.test(selector)) 
      dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
    // If there's a context, create a collection on that context first, and select
    // nodes from there
    else if (context !== undefined) return $(context).find(selector)
    // And last but no least, if it's a CSS selector, use it to select nodes.
    else dom = zepto.qsa(document, selector)
  }
  // create a new Zepto collection from the nodes found
  return zepto.Z(dom, selector)
}

zepto.fragment

  • 由給定的 html 字符串生成 DOM 元素
  • 返回由 DOM 元素組成的數組
zepto.fragment = function(html, name, properties) {
  var dom, nodes, container

  // 判斷是否空標籤,如:<a></a> <p />
  if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1))

  if (!dom) {
    if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>") // 補全雙標籤
    if (name === undefined) name = fragmentRE.test(html) && RegExp.$1
    if (!(name in containers)) name = '*'

    container = containers[name]
    container.innerHTML = '' + html // 使 html 字符串轉換成 dom 元素
    // 將 container 內的元素集合轉換成數組,賦值給dom,並清空 container
    // slice.call 兩個好處:1. 轉換成數組 2. 數組拷貝
    // 這裏爲何不直接將 container 置空,而是一個個移除呢??
    dom = $.each(slice.call(container.childNodes), function(){
      container.removeChild(this)
    })
  }

  // properties 屬性賦值
  if (isPlainObject(properties)) {
    nodes = $(dom)
    $.each(properties, function(key, value) {
      if (methodAttributes.indexOf(key) > -1) nodes[key](value)
      else nodes.attr(key, value)
    })
  }

  return dom
}

zepto.qsa(element, selector)

  • zepto 下的元素選擇器
  • 使用 querySelectorAll 和選項實現相似 css 選擇器,如「#id」
  • 不直接用 querySelector 或 querySelectorAll,只爲更好的性能
  • 規則css

    • selector 以 # 開頭,則用 getElementById
    • selector 以 . 開頭,則用 getElementsByClassName
    • isSimple=/^[/w-]*$/
    • isSimple & 非# & 非.,用 getElementsByTagName
    • 非 Simple,用 querySelectorAll

zepto.Z

  • 生成 zepto 對象集合
zepto.Z = function(dom, selector) {
  return new Z(dom, selector)
}
function Z(dom, selector) {
  var i, len = dom ? dom.length : 0
  for (i = 0; i < len; i++) this[i] = dom[i]
  this.length = len
  this.selector = selector || ''
}
相關文章
相關標籤/搜索