ZeptoソースのDataモジュールを読む


ZeptoDataモジュールは、DOMノード内のdata-*属性のデータを取得し、DOM関連するデータを格納するために使用される.
Zeptoソースシリーズの記事を読んでgithubに載せました.star:reading-zeptoを歓迎します.
ソースバージョン
本稿で読むソースコードはzepto 1である.2.0
GitBook
《reading-zepto》
内部メソッド
attributeData
var data = {}, dataAttr = $.fn.data, camelize = $.camelCase,
    exp = $.expando = 'Zepto' + (+new Date()), emptyArray = []
function attributeData(node) {
  var store = {}
  $.each(node.attributes || emptyArray, function(i, attr){
    if (attr.name.indexOf('data-') == 0)
      store[camelize(attr.name.replace('data-', ''))] =
        $.zepto.deserializeValue(attr.value)
  })
  return store
}

このメソッドは、与えられたnodeのすべてのdata-*属性の値を取得し、storeオブジェクトに格納するために使用される.node.attributes取得したのはノードのすべての属性であるため,遍歴の際に属性名がdata-で始まるか否かを判断する必要がある.
格納するときは、属性名のdata-を外し、残りはアルパカ式に変換してstore対象とするkey.DOMの属性値はいずれも文字列形式であり、操作を容易にするために呼び出されるdeserializeValueメソッドは、対応するデータ型に変換される.このメソッドの具体的な解析については、『Zeptoソースコードを読む属性操作』を参照
setData
function setData(node, name, value) {
  var id = node[exp] || (node[exp] = ++$.uuid),
      store = data[id] || (data[id] = attributeData(node))
  if (name !== undefined) store[camelize(name)] = value
  return store
}

より多くの場合、格納データはDOMに書く必要はなく、メモリに格納するだけでよい.また読み取りDOMのコストは非常に高い.setDataメソッドは対応DOMのデータをstoreオブジェクトに格納します.
var id = node[exp] || (node[exp] = ++$.uuid)

まずnodeexp属性を読み出し、前から見えるexpZeptoタイムスタンプを付けた文字列であり、属性名の一意性を確保し、ユーザがカスタマイズした属性を上書きしないようにしている.ノードのnodeプロパティを設定します.
store = data[id] || (data[id] = attributeData(node))
expからノードの前にキャッシュされたデータを取得し、前にキャッシュされていない場合はexpメソッドを呼び出し、ノード上のdata先頭のすべての属性値を取得し、attributeDataオブジェクトにキャッシュする.
store[camelize(name)] = value

最後に、キャッシュする値を設定します.
getData
function getData(node, name) {
  var id = node[exp], store = id && data[id]
  if (name === undefined) return store || setData(node)
  else {
    if (store) {
      if (name in store) return store[name]
      var camelName = camelize(name)
      if (camelName in store) return store[camelName]
    }
    return dataAttr.call($(node), name)
  }
}
data-ノード指定のキャッシュ値を取得します.
if (name === undefined) return store || setData(node)

属性名が指定されていない場合は、ノードに対応するキャッシュをすべて返し、キャッシュが空の場合はdataメソッドを呼び出し、nodeノード上のsetData先頭の属性値をすべて返します.
if (name in store) return store[name]

指定したnodeキャッシュdata-であれば、結果を返します.
var camelName = camelize(name)
if (camelName in store) return store[camelName]

そうでなければ、指定したnameをアルパカ式に変換し、キャッシュstoreから検索し、見つかった結果を返します.これは互換性nameというパラメータ形式で、より柔軟なstoreを提供しています.
キャッシュに見つからない場合は、camel-nameで検索しますが、実は検索API属性の値です.この方法は後で分析されます.
DOMメソッド
.data()
$.fn.data = function(name, value) {
  return value === undefined ?
    $.isPlainObject(name) ?
    this.each(function(i, node){
    $.each(name, function(key, value){ setData(node, key, value) })
  }) :
  (0 in this ? getData(this[0], name) : undefined) :
  this.each(function(){ setData(this, name, value) })
}
$.fn.dataメソッドは対応data-ノードのキャッシュデータを設定または取得でき、最終的にはそれぞれdataおよびnodeメソッドが呼び出される.
このコードを分析するには、例によって三元表現を一つ一つ分解して、何をしたかを見てみましょう.
value === undefined ?       : this.each(function(){ setData(this, name, value) })

まず第1層を見て、転送setDataおよびgetDataがある場合は、キャッシュの設定であることを示し、すべての要素を巡り、それぞれnameメソッド設定キャッシュを呼び出す.
$.isPlainObject(name) ?
    this.each(function(i, node){
    $.each(name, function(key, value){ setData(node, key, value) })
  }) :      
valueの最初のパラメータは、オブジェクトの伝達値、例えばsetDataもサポートする.オブジェクトの場合、オブジェクトのプロパティは設定するキャッシュ名で、値はキャッシュ値です.
したがって、すべての要素を巡り、dataキャッシュを設定します.
0 in this ? getData(this[0], name) : undefined

最後に、集合が空でないか否かを判断し($(el).data({key1: 'value1'}))、空であればそのままsetData、そうでなければ0 in thisを呼び出し、最初の要素ノード対応undefinedのキャッシュを返す.
.removeData()
$.fn.removeData = function(names) {
  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]
    })
  })
}
getDataキャッシュされたデータを削除するために使用し、転送パラメータがない場合は全てクリアし、転送パラメータがある場合は指定されたデータのみを削除する.name配列として、削除するデータのセットを指定してもよいし、スペースで区切られた文字列としてもよい.
if (typeof names == 'string') names = names.split(/\s+/)
removeDataが文字列であることが検出された場合は、まず文字列を配列に変換します.
return this.each(function(){
  var id = this[exp], store = id && data[id]
 ...
})

要素を巡り、すべての要素を削除し、要素に対応するキャッシュを見つけるnames.
if (store) $.each(names || store, function(key){
  delete store[names ? camelize(this) : key]
})
names存在する場合は指定したデータを削除し、そうでない場合はstoreキャッシュしたデータを全て削除します.
.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)
  }
})

従来のnamesstore方法では、いずれもremoveノードの削除がありますが、emptyノードの削除後は、対応するノードのキャッシュデータにも意味がありません.DOMノードの削除後も、ノードに対応するデータをすべてクリアしてメモリを解放する必要があります.
var elements = this.find('*')
if (methodName === 'remove') elements = elements.add(this)
DOMすべての下位ノードであり、DOMメソッドであれば、ノード自体も除去されるので、自身もノードに加える必要がある.
最後にelementsメソッドを呼び出し、すべてのデータを参照せずにクリアし、データをクリアした後、元のメソッドを呼び出してノードを削除します.
ツールメソッド
$.data
$.data = function(elem, name, value) {
  return $(elem).data(name, value)
}
remove最後に呼び出されたのがremoveDatadataメソッドです.
$.hasData
$.hasData = function(elem) {
  var id = elem[exp], store = id && data[id]
  return store ? !$.isEmptyObject(store) : false
}

エレメントにキャッシュされたデータがあるかどうかを判断します.
まず、キャッシュDOMから、対応dataのキャッシュdataを取り出すことにより、DOMが存在し、かつ空でなければstoreを返し、実際にはstoreを返す.
シリーズ記事
  • Zeptoソースコードのコード構造を読む
  • Zeptoソースの内部を読む方法
  • Zeptoソースのツール関数を読む
  • Zeptoソースの不思議な$を読む
  • Zeptoソースコードの集合を読む操作
  • Zeptoソースコードの集合要素を読む
  • Zeptoソースを読む操作DOM
  • Zeptoソースコードを読むスタイル操作
  • Zeptoソースコードの属性を読む操作
  • ZeptoソースのEventモジュールを読む
  • ZeptoソースのIEモジュールを読む
  • ZeptoソースのCallbacksモジュールを読む
  • ZeptoソースのDeferredモジュールを読む
  • ZeptoソースのAjaxモジュールを読む
  • Zeptoソースコードを読むAssetsモジュール
  • ZeptoソースのSelectorモジュールを読む
  • ZeptoソースのTouchモジュールを読む
  • ZeptoソースのGestureモジュールを読む
  • ZeptoソースのIOS 3モジュールを読む
  • ZeptoソースコードのFxモジュールを読む
  • Zeptoソースコードのfxを読むmethodsモジュール
  • ZeptoソースのStackモジュールを読む
  • Zeptoソースコードを読むFormモジュール
  • 添付文書
  • 訳:Safariモバイル端末による画像リソースの制限の扱い方
  • リファレンス
  • Zeptoにおけるデータキャッシュの原理と実現
  • Element.attributes

  • License
    署名-非商業的使用-演繹禁止4.0国際(CC BY-NC-ND 4.0)
    最後に、すべての文章は同時に微信の公衆番号に送信され、注目を歓迎し、意見を歓迎します.
    作者:対角の反対側