摘要:的模塊用來獲取節點中的屬性的數據,和儲存跟相關的數據。獲取節點指定的緩存值。如果存在,則刪除指定的數據,否則將緩存的數據全部刪除。為所有下級節點,如果為方法,則節點自身也是要被移除的,所以需要將自身也加入到節點中。
Zepto 的 Data 模塊用來獲取 DOM 節點中的 data-* 屬性的數據,和儲存跟 DOM 相關的數據。
讀 Zepto 源碼系列文章已經放到了github上,歡迎star: reading-zepto
源碼版本本文閱讀的源碼為 zepto1.2.0
GitBook《reading-zepto》
內部方法 attributeDatavar 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源碼之屬性操作》
setDatafunction 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)
首先讀取 node 的 exp 屬性,從前面可以看到 exp 是一個 Zepto 加上時間戳的字符串,以確保屬性名的唯一性,避免覆蓋用戶自定義的屬性,如果 node 尚未打上 exp 標記,表明這個節點并沒有緩存的數據,則設置節點的 exp 屬性。
store = data[id] || (data[id] = attributeData(node))
從 data 中獲取節點之前緩存的數據,如果之前沒有緩存數據,則調用 attributeData 方法,獲取節點上所有以 data- 開頭的屬性值,緩存到 data 對象中。
store[camelize(name)] = value
最后,設置需要緩存的值。
getDatafunction 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) } }
獲取 node 節點指定的緩存值。
if (name === undefined) return store || setData(node)
如果沒有指定屬性名,則將節點對應的緩存全部返回,如果緩存為空,則調用 setData 方法,返回 node 節點上所有以 data- 開頭的屬性值。
if (name in store) return store[name]
如果指定的 name 在緩存 store 中,則將結果返回。
var camelName = camelize(name) if (camelName in store) return store[camelName]
否則,將指定的 name 轉換成駝峰式,再從緩存 store 中查找,將找到的結果返回。這是兼容 camel-name 這樣的參數形式,提供更靈活的 API 。
如果緩存中都沒找到,則回退到用 $.fn.data 查找,其實就是查找 data- 屬性上的值,這個方法后面會分析到。
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) }) }
data 方法可以設置或者獲取對應 node 節點的緩存數據,最終分別調用的是 setData 和 getData 方法。
分析這段代碼,照例還是將三元表達式一個一個拆解,來看看都做了什么事情。
value === undefined ? 三元表達式 : this.each(function(){ setData(this, name, value) })
先看第一層,當有傳遞 name 和 value 時,表明是設置緩存,遍歷所有元素,分別調用 setData 方法設置緩存。
$.isPlainObject(name) ? this.each(function(i, node){ $.each(name, function(key, value){ setData(node, key, value) }) }) : 三元表達式
data 的第一個參數還支持對象的傳值,例如 $(el).data({key1: "value1"}) 。如果是對象,則對象里的屬性為需要設置的緩存名,值為緩存值。
因此,遍歷所有元素,調用 setData 設置緩存。
0 in this ? getData(this[0], name) : undefined
最后,判斷集合是否不為空( 0 in this ), 如果為空,則直接返回 undefined ,否則,調用 getData ,返回第一個元素節點對應 name 的緩存。
.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] }) }) }
removeData 用來刪除緩存的數據,如果沒有傳遞參數,則全部清空,如果有傳遞參數,則只刪除指定的數據。
names 可以為數組,指定需要刪除的一組數據,也可以為以空格分割的字符串。
if (typeof names == "string") names = names.split(/s+/)
如果檢測到 names 為字符串,則先將字符串轉換成數組。
return this.each(function(){ var id = this[exp], store = id && data[id] ... })
遍歷元素,對所有的元素都進行刪除操作,找出和元素對應的緩存 store 。
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) } })
原有的 remove 和 empty 方法,都會有 DOM 節點的移除,在移除 DOM 節點后,對應節點的緩存數據也就沒有什么意義了,所有在移除 DOM 節點后,也需要將節點對應的數據也清空,以釋放內存。
var elements = this.find("*") if (methodName === "remove") elements = elements.add(this)
elements 為所有下級節點,如果為 remove 方法,則節點自身也是要被移除的,所以需要將自身也加入到節點中。
最后調用 removeData 方法,不傳參清空所有數據,在清空數據后,再調用原來的方法移除節點。
工具方法 $.data$.data = function(elem, name, value) { return $(elem).data(name, value) }
data 最后調用的也就是 DOM 的 data 方法。
$.hasData$.hasData = function(elem) { var id = elem[exp], store = id && data[id] return store ? !$.isEmptyObject(store) : false }
判斷某個元素是否已經有緩存的數據。
首先通過從緩存 data 中,取出對應 DOM 的緩存 store ,如果 store 存在,并且不為空,則返回 true ,其實情況返回 false 。
系列文章讀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源碼之IOS3模塊
讀Zepto源碼之Fx模塊
讀Zepto源碼之fx_methods模塊
讀Zepto源碼之Stack模塊
讀Zepto源碼之Form模塊
附文譯:怎樣處理 Safari 移動端對圖片資源的限制
參考Zepto中數據緩存原理與實現
Element.attributes
License署名-非商業性使用-禁止演繹 4.0 國際 (CC BY-NC-ND 4.0)
最后,所有文章都會同步發送到微信公眾號上,歡迎關注,歡迎提意見:
作者:對角另一面
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/89286.html
摘要:模塊是為解決移動版加載圖片過大過多時崩潰的問題。因為沒有處理過這樣的場景,所以這部分的代碼解釋不會太多,為了說明這個問題,我翻譯了這篇文章作為附文怎樣處理移動端對圖片資源的限制,更詳細地解釋了這個模塊的應用場景。 assets 模塊是為解決 Safari 移動版加載圖片過大過多時崩潰的問題。因為沒有處理過這樣的場景,所以這部分的代碼解釋不會太多,為了說明這個問題,我翻譯了《How to...
摘要:私有變量用來臨時存放配置中的,即請求成功后執行的回調函數名,該配置可以為類型。是根據配置得出的回調函數名。接下來,將的占位符,替換成回調函數名,最后將插入到頁面中,發送請求。 Ajax 模塊也是經常會用到的模塊,Ajax 模塊中包含了 jsonp 的現實,和 XMLHttpRequest 的封裝。 讀 Zepto 源碼系列文章已經放到了github上,歡迎star: reading-...
摘要:讀源碼系列文章已經放到了上,歡迎源碼版本本文閱讀的源碼為改寫原有的方法模塊改寫了以上這些方法,這些方法在調用的時候,會為返回的結果添加的屬性,用來保存原來的集合。方法的分析可以看讀源碼之模塊。 Stack 模塊為 Zepto 添加了 addSelf 和 end 方法。 讀 Zepto 源碼系列文章已經放到了github上,歡迎star: reading-zepto 源碼版本 本文閱讀的...
摘要:模塊基于上的事件的封裝,利用屬性,封裝出系列事件。這個判斷需要引入設備偵測模塊。然后是監測事件,根據這三個事件,可以組合出和事件。其中變量對象和模塊中的對象的作用差不多,可以先看看讀源碼之模塊對模塊的分析。 Gesture 模塊基于 IOS 上的 Gesture 事件的封裝,利用 scale 屬性,封裝出 pinch 系列事件。 讀 Zepto 源碼系列文章已經放到了github上,歡...
摘要:是禁用回調函數,實質是將回調函數列表置為,同時也將和置為,調用后,等方法不再生效,這些方法的首要條件是存在。效果等同于禁用回調函數。 Callbacks 模塊并不是必備的模塊,其作用是管理回調函數,為 Defferred 模塊提供支持,Defferred 模塊又為 Ajax 模塊的 promise 風格提供支持,接下來很快就會分析到 Ajax模塊,在此之前,先看 Callbacks 模...
閱讀 852·2023-04-25 23:59
閱讀 3748·2021-10-08 10:04
閱讀 1684·2019-08-30 14:05
閱讀 1018·2019-08-30 13:58
閱讀 494·2019-08-29 18:41
閱讀 1130·2019-08-29 17:15
閱讀 2324·2019-08-29 14:13
閱讀 2749·2019-08-29 13:27