2

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 最终返回的结果是一个数组,每个数组项为包含 namevalue 属性的对象。其中 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)) 如果是 radiocheckbox 时,则必须要选中,这个也很好理解,如果没有选中,也不会有值需要处理。

然后调用 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 序列化 namevalue 的值,并用 = 号拼接成字符串,存进新的数组中,最后调用 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 ,提交表单。

注意 eqget 的区别, eq 返回的是 Zepto 对象,而 get 返回的是 DOM 元素。

系列文章

  1. 读Zepto源码之代码结构
  2. 读Zepto源码之内部方法
  3. 读Zepto源码之工具函数
  4. 读Zepto源码之神奇的$
  5. 读Zepto源码之集合操作
  6. 读Zepto源码之集合元素查找
  7. 读Zepto源码之操作DOM
  8. 读Zepto源码之样式操作
  9. 读Zepto源码之属性操作
  10. 读Zepto源码之Event模块
  11. 读Zepto源码之IE模块
  12. 读Zepto源码之Callbacks模块
  13. 读Zepto源码之Deferred模块
  14. 读Zepto源码之Ajax模块
  15. 读Zepto源码之Assets模块
  16. 读Zepto源码之Selector模块
  17. 读Zepto源码之Touch模块
  18. 读Zepto源码之Gesture模块
  19. 读Zepto源码之IOS3模块
  20. 读Zepto源码之Fx模块
  21. 读Zepto源码之fx_methods模块
  22. 读Zepto源码之Stack模块

附文

参考

License

署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)

最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:

作者:对角另一面


对角另一面
1.4k 声望79 粉丝

踏在路上交叉点,你在对角另一面。