Zepto源碼之data模塊

;(function($){
  var data = {}, dataAttr = $.fn.data, camelize = $.camelCase,
    exp = $.expando = 'Zepto' + (+new Date()), emptyArray = []


  // 獲取 node 節點的指定屬性名的值
  function getData(node, name) {
    // 讀取 node 的 exp 屬性,直接賦值給 id 。然後拿到對應 node 的 store
    var id = node[exp], store = id && data[id]
    // 如果屬性名不存在,那麼返回全部屬性 store 。如果 store 存在,直接返回,不存在,通過setData() 方法拿到一個返回
    if (name === undefined) return store || setData(node)
    else {
      if (store) {
        // 如果 name 存在於 store 中,直接返回結果。不如果不存在,那麼轉化成駝峯再返回一次結果
        if (name in store) return store[name]
        var camelName = camelize(name)
        if (camelName in store) return store[camelName]
      }
      // 如果有 name , store 但是在 store 中找不到,那麼使用 dataAttr 找一遍
      return dataAttr.call($(node), name)
    }
  }

  // 給 node 節點設置屬性,另外該屬性是存儲在內存中的,並沒有真正的操作 DOM 節點
  function setData(node, name, value) {
    // 讀取 node 的 exp 屬性,如果存在那麼直接賦值給 id 。如果不存在那麼新建一個賦值給 id 。注意新建的時候使用的是一個時間戳字符串,這樣就可以有效的避免覆蓋用戶的私有屬性。
    var id = node[exp] || (node[exp] = ++$.uuid),
    // 從 node 節點拿到之前緩存的數據,如果沒有緩存,那麼調用 attributeData 方法來緩存。
      store = data[id] || (data[id] = attributeData(node))
    // 設置需要緩存的值
    if (name !== undefined) store[camelize(name)] = value
    return store
  }

  // 用來獲取給定的 node 節點的所有 data-* 自定義屬性值 ,並儲存到 store 對象中
  function attributeData(node) {
    var store = {}
    // 先拿到該 node 節點的 attributes 數組,如果不存在,賦值爲空數組,然後遍歷該數組
    $.each(node.attributes || emptyArray, function(i, attr){
      // 如果屬性名是 data- 開頭,那就說明是我們需要的自定義屬性,將其除去開頭的 data- 標識,轉化爲駝峯命名並存入到 store 中
      if (attr.name.indexOf('data-') == 0)
        store[camelize(attr.name.replace('data-', ''))] =
          $.zepto.deserializeValue(attr.value)
    })
    return store
  }

  // 用於設置或者獲取 data-* 數據
  $.fn.data = function(name, value) {
  // 判斷 value 是否存在,如果存在,那麼說明是設置,如果不存在,那麼說明是獲取
    return value === undefined ?
      // 判斷是不是一個"正經"的對象,如果是的話,遍歷對象屬性,將其使用 setData設置
      $.isPlainObject(name) ?
        this.each(function(i, node){
          $.each(name, function(key, value){ setData(node, key, value) })
        }) :
        // 不是一個"正經"對象的話,那麼查看目前操作的 zepto 對象是否存在節點,如果存在節點返回第一個節點的對應屬性,如果不存在,返回undefined
        (0 in this ? getData(this[0], name) : undefined) :
      // 這就是存在 value 的情況,遍歷使用 setData 賦值
      this.each(function(){ setData(this, name, value) })
  }

  // 用於設置或者獲取指定節點的 data-* 數據
  $.data = function(elem, name, value) {
    return $(elem).data(name, value)
  }

  // 判斷是否存在 data-* 自定義屬性
  $.hasData = function(elem) {
    var id = elem[exp], store = id && data[id]
    return store ? !$.isEmptyObject(store) : false
  }

  // 刪除對應的 names 屬性
  $.fn.removeData = function(names) {
    // 先判斷是不是字符串,如果是的話,就以空爲分割,分割成數組,這樣就可以刪除類似於 "hello world pika",這樣設置的 "hello", "world", "pika" 三個屬性了,也方面下面使用 each 方法遍歷
    if (typeof names == 'string') names = names.split(/\s+/)
    return this.each(function(){
      var id = this[exp], store = id && data[id]
      if (store) $.each(names || store, function(key){
        delete store[names ? camelize(this) : key]
      })
    })
  }

  // 改寫 $.fn 上面的 remove , empty 方法
  ;['remove', 'empty'].forEach(function(methodName){
    var origFn = $.fn[methodName]
    $.fn[methodName] = function() {
      var elements = this.find('*')
      if (methodName === 'remove') elements = elements.add(this)
      elements.removeData()
      return origFn.call(this)
    }
  })
})(Zepto)
發佈了88 篇原創文章 · 獲贊 41 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章