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