zepto源码分析之form模块

前言

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(原理与具体实现细节)

1 篇内容引用
3.6k 声望
6.1k 粉丝
0 条评论
推荐阅读
面试官:Vue3响应式系统都不会写,还敢说精通?
也许你我素未谋面,但很可能相见恨晚,我是前端胖头鱼前言都说今年是最惨工作年,大厂裁员,小厂跟风,简历投了几百封回信的寥寥无几,金三银四怕是成了铜三铁四,冷冷清清,凄凄惨惨。但是今天的主角,小帅同学...

前端胖头鱼5阅读 4.3k评论 2

封面图
正则表达式实例
收集在业务中经常使用的正则表达式实例,方便以后进行查找,减少工作量。常用正则表达式实例1. 校验基本日期格式 {代码...} {代码...} 2. 校验密码强度密码的强度必须是包含大小写字母和数字的组合,不能使用特殊...

寒青56阅读 8.4k评论 11

JavaScript有用的代码片段和trick
平时工作过程中可以用到的实用代码集棉。判断对象否为空 {代码...} 浮点数取整 {代码...} 注意:前三种方法只适用于32个位整数,对于负数的处理上和Math.floor是不同的。 {代码...} 生成6位数字验证码 {代码...} ...

jenemy48阅读 7k评论 12

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木75阅读 7.1k评论 16

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs42阅读 6.8k评论 12

封面图
从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木45阅读 8.5k评论 6

CSS 绘制一只思否猫
欢迎关注我的公众号:前端侦探练习 CSS 有一个比较有趣的方式,就是发挥想象,绘制各式各样的图案,比如来绘制一只思否猫?思否猫,SegmentFault 思否的吉祥物,是一只独一无二、特立独行、热爱自由的(>^ω^&lt...

XboxYan46阅读 3.2k评论 14

封面图
3.6k 声望
6.1k 粉丝
宣传栏