读Zepto源码之Form模块

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)

作者:对角另一面

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏iKcamp

如何实现VM框架中的数据绑定

作者:佳杰 本文原创,转载请注明作者及出处 如何实现VM框架中的数据绑定 一:数据绑定概述 视图(view)和数据(model)之间的绑定 二:数据绑定目的...

3448
来自专栏技术分享

.NET/ASP.NET MVC Controller 控制器(IController控制器的创建过程)

阅读目录: 1.开篇介绍 2.ASP.NETMVC IControllerFactory 控制器工厂接口 3.ASP.NETMVC DefaultControl...

2196
来自专栏贺贺的前端工程师之路

React Native生命周期生命周期props和state

然后,准备加载组件,会调用 componentWillMount() ,其原型如下: void componentWillMount() 这个函数调用时机是...

602
来自专栏老马寒门IT

02-老马jQuery教程-jQuery事件处理

在DOM中DOM0级绑定事件的方式是直接给事件属性赋值,但是这样有个缺点就是每次指定的事件处理程序会把之前的覆盖掉。

1980
来自专栏老司机的简书

老司机读书笔记——Weex学习笔记

Weex整体上与Vue语法大概一直,基本用法由阿里进行二次封装。以下主要介绍Weex的一些内置组件。

1324
来自专栏移动开发之家

IJKPlayer问题集锦之不定时更新

1、IJKPlayer 不像系统播放器会给你旋转视频角度,所以你需要通过onInfo的what == IMediaPlayer.MEDIA_INFO_VIDEO...

1174
来自专栏Kevin-ZhangCG

Tapestry3.0开发概论

 tapestry是平行于struts/Spring MVC/webwork /jsf等开发工具的语言。tapestry是基于组件的开发工具。它具有组件的可重...

842
来自专栏滕先生的博客

XML解析方式及GData框架使用一、概念二、XML解析SAM方式(只读)三、DOM方式解析(可读写)四、GData写入功能,生成XML

2616
来自专栏LeoXu的博客

Tapestry 教程(五)实现Hi-Lo猜谜游戏

在这个游戏中,计算机会选择一个介于1到10之间的数字。你尝试猜出这个数字,点击一些链接。最后,计算器会告诉你确认目标数字你需要猜多少次。即使是像这样一个简单的示...

842
来自专栏向前进

【笔记】HybridApp中使用Promise化的JS-Bridge

背景: HybridApp,前端采用JS-bridge的方式调用Native的接口,如获取设备信息、拍照、人脸识别等 前端封装了调用库,每次调用Native接口...

3184

扫码关注云+社区