Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zepto源码分析之form模块 #7

Open
qianlongo opened this issue Oct 1, 2017 · 0 comments
Open

Zepto源码分析之form模块 #7

qianlongo opened this issue Oct 1, 2017 · 0 comments

Comments

@qianlongo
Copy link
Owner

qianlongo commented Oct 1, 2017

前言

JavaScript最初的一个应用场景就是分担服务器处理表单的责任,打破处处依赖服务器的局面,这篇文章主要介绍zepto中form模块关于表单处理的几个方法,serializeserializeArraysubmit

原文链接

github项目地址

表单相关回顾

在开始学些form模块相关方法前,我们先来回顾一下表单提交时,浏览器是怎么样将数据发送给服务器的(以下内容摘自《JavaScript高级程序设计》第14章 14.4节 表单序列化)

  1. 对表单字段的名称和值进行URL编码,使用&分隔。
  2. 不发送禁用的表单字段。(也就是属性disabled为true的)
  3. 只发送勾选的复选框和单选按钮
  4. 不发送type为reset和button的按钮
  5. 多选选择框中每个选择的值单独一个条目
  6. 在单击提交按钮表单的情况下,也会发送提交按钮的value值,否则不发送提交按钮。
  7. select元素的值,就是选中的option元素的value属性的值,如果option元素没有value属性,则是option元素的文本值。 在表单序列化得过程中,一般不包含任何按钮字段,因为结果字符串很可能是通过其他方式提交的,除此之外其他规则都应该遵循。

有了上面的知识的回顾,接下来我们开始看zepto中serializeserializeArray的实现

serializeArray

因为serialize依赖serializeArray的实现,所以我们先来看看它是怎么实现的。而他的作用是把form表单序列化成一个由 name 和 value 属性组成的对象的数组。形如:

[
  {name: 'qianlongo', value: 'haha'},
  {name: 'wangmin', value: 'heihei'}
]

源代码

 $.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相关方法。一开始声明了name,type, result三个变量,分别存储表单控件的name属性,type属性,以及最后函数执行完成后要返回的数组。

首先通过this[0]判断有未选中表单元素,如果没有返回的结果就是一个空数组了。如果选中了,则对该表单的相关控件(form.elements表示表单中所有控件的集合)进行遍历。

获取单个控件的类型(type),name属性(name),再接着就是判断符合提交到服务器端的表单控件条件了。

  1. 需要有name属性(条件为"真")
  2. 不能是fieldset元素
  3. 不能是已经禁止的元素(即disable为true)
  4. 不能是submit、reset、button、file等元素
  5. 对于单选和多选控件,只发送已经勾选的。

在上面的条件都满足的条件下,调用add函数并将通过$(elements).val()获取到的值传入。

add函数的逻辑也非常简单。如果value是数组,则将value数组递归的每一项传入add。不是数组就是直接按照{ name: name, value: value }形式推入result了。

不过什么时候value会为数组呢?我们需要从zepto模块的val函数实现看起

val函数实现

function val (value) {
  if (0 in arguments) {
    if (value == null) value = ""
    return this.each(function (idx) {
      this.value = funcArg(this, value, idx, this.value)
    })
  } else {
    // 主要看这里,multiple是用来设置下拉列表是否可以多选的。
    // 如果是多选的,则选择被选中(即selected为true)的元素并通过pluck方法,读取该元素的value值,最后返回的是一个数组
    return this[0] && (this[0].multiple ?
      $(this[0]).find('option').filter(function () { return this.selected }).pluck('value') :
      this[0].value)
  }
}

serialize

将表单内容序列化为查询字符串。类似name=qianlongo&sex=boy

源代码

$.fn.serialize = function(){
  var result = []
  this.serializeArray().forEach(function(elm){
    // 每个表单的name和value都通过encodeURIComponent编码
    result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value))
  })
  // 最后通过&符号分割
  return result.join('&')
}

有了serializeArray的基础,serialize就是将相应的name和value都通过encodeURIComponent编码,然后用&符号进行分割,也就达到了我们要的结果。

submit

有两种用法,当传入了一个回调函数的时候,是给指定的表单的submit事件添加一个回调处理函数。

如果没有传入回调函数则触发当前表单submit事件,并且执行默认的提交表单行为(前提是没有阻止浏览器默认行为)

源代码

$.fn.submit = function(callback) {
  // 如果传了回调函数,则在选中的元素上添加submit事件
  if (0 in arguments) this.bind('submit', callback)
  // 否则在没有传递回调函数的情况下,并且选中有表单元素  
  else if (this.length) {
    var event = $.Event('submit')
    // 触发选中的第一个表单的是submit事件,注意这里只是手动触发绑定的submit事件,并不会提交表单
    this.eq(0).trigger(event)
    // 如果没有阻止默认事件,便调用form.submit()提交表单
    if (!event.isDefaultPrevented()) this.get(0).submit()
  }
  return this
}

结尾

以上是zepto form模块的相关源码分析,欢迎大家指正。

文章记录

form模块

  1. zepto源码分析之form模块

zepto模块

  1. 这些Zepto中实用的方法集
  2. Zepto核心模块之工具方法拾遗

event模块

  1. mouseenter与mouseover为何这般纠缠不清?
  2. 向zepto.js学习如何手动触发DOM事件
  3. 谁说你只是"会用"jQuery?

ajax模块

  1. 原来你是这样的jsonp(原理与具体实现细节)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant