Form 模塊處理的是表單提交。表單提交包含兩部分,一部分是格式化表單數據,另一部分是觸發 submit 事件,提交表單。
讀 Zepto 源碼系列文章已經放到了github上,歡迎star: reading-zepto
源碼版本
本文閲讀的源碼為 zepto1.2.0
GitBook
《reading-zepto》
.serializeArray()
$.fn.serializeArray = function() {
var name, type, result = [],
add = function(value) {
if (value.forEach) return value.forEach(add)
result.push({ name: name, value: value })
}
if (this[0]) $.each(this[0].elements, function(_, field){
type = field.type, name = field.name
if (name && field.nodeName.toLowerCase() != 'fieldset' &&
!field.disabled && type != 'submit' && type != 'reset' && type != 'button' && type != 'file' &&
((type != 'radio' && type != 'checkbox') || field.checked))
add($(field).val())
})
return result
}
serializeArray 是格式化部分的核心方法,後面的 serialize 方法內部調用的也是 serializeArray 方法。
serializeArray 最終返回的結果是一個數組,每個數組項為包含 name 和 value 屬性的對象。其中 name 為表單元素的 name 屬性值。
add函數
add = function(value) {
if (value.forEach) return value.forEach(add)
result.push({ name: name, value: value })
}
表單的值交由 add 函數處理,如果值為數組(支持 forEach ) 方法,則調用 forEach 遍歷,繼續由 add 函數處理。否則將結果存入數組 result 中。最後返回的結果也是這個 result。
遍歷表單元素
if (this[0]) $.each(this[0].elements, function(_, field){
type = field.type, name = field.name
if (name && field.nodeName.toLowerCase() != 'fieldset' &&
!field.disabled && type != 'submit' && type != 'reset' && type != 'button' && type != 'file' &&
((type != 'radio' && type != 'checkbox') || field.checked))
add($(field).val())
})
如果集合中有多個表單,則只處理第一個表單的表單元素。this[0].elements 用來獲取第一個表單所有的表單元素。
type 為表單類型,name 為表單元素的 name 屬性值。
這一大段代碼的關鍵在 if 中的條件判斷,其實是將一些無關的表單元素排除,只處理符合條件的表單元素。
以下一個條件一個條件來分析:
field.nodeName.toLowerCase() != 'fieldset'排除fieldset元素;!field.disabled排除禁用的表單,已經禁用了,肯定是沒有值需要提交的了;type != 'submit'排除確定按鈕;type != 'reset'排除重置按鈕;type != 'button'排除按鈕;type != 'file'排除文件選擇控件;((type != 'radio' && type != 'checkbox') || field.checked))如果是radio或checkbox時,則必須要選中,這個也很好理解,如果沒有選中,也不會有值需要處理。
然後調用 add 方法,將表單元素的值獲取到交由其處理。
.serialize()
$.fn.serialize = function(){
var result = []
this.serializeArray().forEach(function(elm){
result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value))
})
return result.join('&')
}
表單元素處理完成後,最終是要拼成如 name1=value1&name2=value2&... 的形式,serialize 方法要做的就是這部分事情。
這裏對 serizlizeArray 返回的數組再做進一步的處理,首先用 encodeURIComponent 序列化 name 和 value 的值,並用 = 號拼接成字符串,存進新的數組中,最後調用 join 方法,用 & 將各項拼接起來。
.submit()
$.fn.submit = function(callback) {
if (0 in arguments) this.bind('submit', callback)
else if (this.length) {
var event = $.Event('submit')
this.eq(0).trigger(event)
if (!event.isDefaultPrevented()) this.get(0).submit()
}
return this
}
處理完數據,接下來該到提交了。
if (0 in arguments) this.bind('submit', callback)
如果有傳遞迴調函數 callback ,則在表單上綁定 submit 事件,以 callback 作為事件的回調。
else if (this.length) {
var event = $.Event('submit')
this.eq(0).trigger(event)
if (!event.isDefaultPrevented()) this.get(0).submit()
}
否則手動綁定 submit 事件,如果沒有阻止瀏覽器的默認事件,則在第一個表單上觸發 submit ,提交表單。
注意 eq 和 get 的區別, eq 返回的是 Zepto 對象,而 get 返回的是 DOM 元素。
系列文章
- 讀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模塊
附文
- 譯:怎樣處理 Safari 移動端對圖片資源的限制
參考
- zepto源碼分析之form模塊
- HTMLFormElement.elements
License
署名-非商業性使用-禁止演繹 4.0 國際 (CC BY-NC-ND 4.0)
最後,所有文章都會同步發送到微信公眾號上,歡迎關注,歡迎提意見:
作者:對角另一面