接收表单数据:serialize()函数解析

一、form-serialize作用与引入

作用:
form-serialize可以快速收集表单数据,按照使用者意愿转化为对象或字符串输出,以便于提交至服务器。
引入:
form-serialize不是浏览器自带的JS方法,而是第三方工具库。可以直接通过scrip标签引入:

<script src="https://cdn.jsdelivr.net/npm/form-serialize@0.7.2/form-serialize.min.js"></script>

或者到npm网站搜索form-serialize(),将代码文件保存到本地引入,也可以在终端安装后直接使用require获取:

npm install form-serialize
import serialize from 'form-serialize';const data = serialize(form, { hash: true, empty: true });

二、输出

serialize的使用方法为:

const form=document.querySelector('form')
/*
假设表单内容为:
<form action=""><input type="text" name="username" id="" value="user"><input type="text" name="age" id="" value="18"><input type="text" name="infor" id="" value="">
</form>
*/
//1.转化为query string参数
const data=serialize(form)
//2.转化为没有空内容的对象
const dataobj=serialize(form,hash:true)
//3.转化为有空内容的对象
const dataobjWithEempty=serialize(form,{hash:true,empty:true})
  • 方法1传出为:www.example.com?username=user&age=18
    这个形式的字符串可以直接作为AJAX请求的body或URL的query string
  • 方法2传出为:
dataobj={username:'user',age:18
}
  • 方法3传出为:
dataobj={username:'user',age:18,infor:''
}

发现区别了吗?方法一传出query string字符串,方法二传出不含空白字符串的表单数据对象,方法三会将收集到的所有信息传出为对象。其中:

  • hash在代表哈希表,是一种键值对应的对象,所以{hash:true}就代表传出对象。
  • empty:true则代表传出对象中包含空白字符串,接下来我们观察底层代码如何实现。

从npm下载的完整js代码放在文末

三、解析

serialize函数定义:

function serialize(form, options) {if (typeof options != 'object') {options = { hash: !!options };}else if (options.hash === undefined) {options.hash = true;}var result = (options.hash) ? {} : '';var serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize);var elements = form && form.elements ? form.elements : [];//Object store each radio and set if it's empty or notvar radio_store = Object.create(null);for (var i=0 ; i<elements.length ; ++i) {var element = elements[i];// ingore disabled fieldsif ((!options.disabled && element.disabled) || !element.name) {continue;}// ignore anyhting that is not considered a success fieldif (!k_r_success_contrls.test(element.nodeName) ||k_r_submitter.test(element.type)) {continue;}var key = element.name;var val = element.value;// we can't just use element.value for checkboxes cause some browsers lie to us// they say "on" for value when the box isn't checkedif ((element.type === 'checkbox' || element.type === 'radio') && !element.checked) {val = undefined;}// If we want empty elementsif (options.empty) {// for checkboxif (element.type === 'checkbox' && !element.checked) {val = '';}// for radioif (element.type === 'radio') {if (!radio_store[element.name] && !element.checked) {radio_store[element.name] = false;}else if (element.checked) {radio_store[element.name] = true;}}// if options empty is true, continue only if its radioif (val == undefined && element.type == 'radio') {continue;}}else {// value-less fields are ignored unless options.empty is trueif (!val) {continue;}}// multi select boxesif (element.type === 'select-multiple') {val = [];var selectOptions = element.options;var isSelectedOptions = false;for (var j=0 ; j<selectOptions.length ; ++j) {var option = selectOptions[j];var allowedEmpty = options.empty && !option.value;var hasValue = (option.value || allowedEmpty);if (option.selected && hasValue) {isSelectedOptions = true;// If using a hash serializer be sure to add the// correct notation for an array in the multi-select// context. Here the name attribute on the select element// might be missing the trailing bracket pair. Both names// "foo" and "foo[]" should be arrays.if (options.hash && key.slice(key.length - 2) !== '[]') {result = serializer(result, key + '[]', option.value);}else {result = serializer(result, key, option.value);}}}// Serialize if no selected options and options.empty is trueif (!isSelectedOptions && options.empty) {result = serializer(result, key, '');}continue;}result = serializer(result, key, val);}// Check for all empty radio buttons and serialize them with key=""if (options.empty) {for (var key in radio_store) {if (!radio_store[key]) {result = serializer(result, key, '');}}}return result;
}

我们可以发现,要求传入参数为:(form,options),form为我们获取的表单对象,options可以省略。
首先,程序查询传入参数:

    if (typeof options != 'object') {options = { hash: !!options };}else if (options.hash === undefined) {options.hash = true;}

如果options不是对象,就使用!!强行将options转化为bool值,存储到hash属性中,并将这对键值转化为对象。

这允许我们在使用serialize转化对象时简写:const dataobj=serialize(form,true)

完成了简写判断,进行options为对象时的判断:

	//result为传出参数//hash为:真-result初始化为对象;假-初始化为字符串var result = (options.hash) ? {} : '';//options.serializer存在,直接使用,若不存在://hash为true,调用hash_serializer//hash为false,调用str_serializevar serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize);

其中:

  • hash_serializer:自定义函数,将表单数据序列化为 JavaScript 对象。
  • str_serialize:自定义函数,将表单数据序列化为 URL 编码的字符串。

接下来,接收radio类型单选按钮数据,创建空对象:

	//将表单格式化为数组,进行遍历var elements = form && form.elements ? form.elements : [];//创建空对象var radio_store = Object.create(null);

之后进入遍历elments的for循环

在下面这段代码中:

  • 过滤掉不需要序列化的字段:
  • 禁用的字段(除非 options.disabled 为 true)。
  • 没有 name 属性的字段。
  • 不属于“成功控件(表单要收集的数据)”的字段。
        if ((!options.disabled && element.disabled) || !element.name) {continue;}// ignore anyhting that is not considered a success fieldif (!k_r_success_contrls.test(element.nodeName) ||k_r_submitter.test(element.type)) {continue;}

在下面这段代码中:

  • 设置表单的键与值
  • 检查复选框与单选框是否被选中,若没有,标记为undefined,表示不该被记录。
		var key = element.name;var val = element.value;if ((element.type === 'checkbox' || element.type === 'radio') && !element.checked) {val = undefined;}

获取属性:

// If we want empty elements-如果options.empty为true,即我们需要空白字符串值
if (options.empty) {// for checkbox-获取复选框值if (element.type === 'checkbox' && !element.checked) {val = '';}// for radio-获取单选框值if (element.type === 'radio') {if (!radio_store[element.name] && !element.checked) {radio_store[element.name] = false;}else if (element.checked) {radio_store[element.name] = true;}}// if options empty is true, continue only if its radio//如果控件无有效值(未被选择)且为单选框,直接进行下次迭代if (val == undefined && element.type == 'radio') {continue;}}else {//不需要空字符串的情况,没有值直接跳过// value-less fields are ignored unless options.empty is trueif (!val) {continue;}}

接下来进行遍历中的多选下拉选项获取(单选下拉可以直接通过下拉对象的value属性获取)

if (element.type === 'select-multiple') {//初始化值数组val = [];//获取选项数组,用于遍历var selectOptions = element.options;//每次迭代初始化未被选择bool类型var isSelectedOptions = false;for (var j=0 ; j<selectOptions.length ; ++j) {var option = selectOptions[j];//该选项是否被允许空值var allowedEmpty = options.empty && !option.value;//当前选项是否有有效值:有真值或被允许空值var hasValue = (option.value || allowedEmpty);//是否被选择,是否有有效值if (option.selected && hasValue) {//给bool值赋值:被选中isSelectedOptions = true;// 处理格式/*如果用户配置了 options.hash 为 true,表示需要将结果序列化为对象格式。key.slice(key.length - 2) !== '[]':检查当前选项的 name 属性是否以 [] 结尾。如果没有以 [] 结尾,则在键名后面追加 [],以确保多选下拉框的值被正确处理为数组。递归调用 serializer:调用序列化函数(hash_serializer 或 str_serialize),将当前选项的键值对添加到结果中:如果是对象序列化(hash_serializer),会将值存储为数组。如果是字符串序列化(str_serialize),会将值编码为 URL 查询字符串格式。*/if (options.hash && key.slice(key.length - 2) !== '[]') {result = serializer(result, key + '[]', option.value);}else {result = serializer(result, key, option.value);}}}// Serialize if no selected options and options.empty is trueif (!isSelectedOptions && options.empty) {result = serializer(result, key, '');}continue;}

这是获取复选下拉的部分,接下来:

递归调用,将当前表单键值对序列化添加到结果中,以便于处理正确的嵌套逻辑。

result = serializer(result, key, val);

检查所有的值都不为空/未定义

	//如果允许空字符串if (options.empty) {for (var key in radio_store) {if (!radio_store[key]) {result = serializer(result, key, '');}}}//若未允许空字符串,在前面值为空的对象会直接跳过进入下次迭代

返回结果:

return result;

四、form-serialize.js文件完整代码

// get successful control from form and assemble into object
// http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2// types which indicate a submit action and are not successful controls
// these will be ignored
var k_r_submitter = /^(?:submit|button|image|reset|file)$/i;// node names which could be successful controls
var k_r_success_contrls = /^(?:input|select|textarea|keygen)/i;// Matches bracket notation.
var brackets = /(\[[^\[\]]*\])/g;// serializes form fields
// @param form MUST be an HTMLForm element
// @param options is an optional argument to configure the serialization. Default output
// with no options specified is a url encoded string
//    - hash: [true | false] Configure the output type. If true, the output will
//    be a js object.
//    - serializer: [function] Optional serializer function to override the default one.
//    The function takes 3 arguments (result, key, value) and should return new result
//    hash and url encoded str serializers are provided with this module
//    - disabled: [true | false]. If true serialize disabled fields.
//    - empty: [true | false]. If true serialize empty fields
function serialize(form, options) {if (typeof options != 'object') {options = { hash: !!options };}else if (options.hash === undefined) {options.hash = true;}//真:初始化为对象,假:初始化为字符串var result = (options.hash) ? {} : '';var serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize);var elements = form && form.elements ? form.elements : [];//Object store each radio and set if it's empty or notvar radio_store = Object.create(null);for (var i=0 ; i<elements.length ; ++i) {var element = elements[i];// ingore disabled fieldsif ((!options.disabled && element.disabled) || !element.name) {continue;}// ignore anyhting that is not considered a success fieldif (!k_r_success_contrls.test(element.nodeName) ||k_r_submitter.test(element.type)) {continue;}var key = element.name;var val = element.value;// we can't just use element.value for checkboxes cause some browsers lie to us// they say "on" for value when the box isn't checkedif ((element.type === 'checkbox' || element.type === 'radio') && !element.checked) {val = undefined;}// If we want empty elementsif (options.empty) {// for checkboxif (element.type === 'checkbox' && !element.checked) {val = '';}// for radioif (element.type === 'radio') {if (!radio_store[element.name] && !element.checked) {radio_store[element.name] = false;}else if (element.checked) {radio_store[element.name] = true;}}// if options empty is true, continue only if its radioif (val == undefined && element.type == 'radio') {continue;}}else {// value-less fields are ignored unless options.empty is trueif (!val) {continue;}}// multi select boxesif (element.type === 'select-multiple') {val = [];var selectOptions = element.options;var isSelectedOptions = false;for (var j=0 ; j<selectOptions.length ; ++j) {var option = selectOptions[j];var allowedEmpty = options.empty && !option.value;var hasValue = (option.value || allowedEmpty);if (option.selected && hasValue) {isSelectedOptions = true;// If using a hash serializer be sure to add the// correct notation for an array in the multi-select// context. Here the name attribute on the select element// might be missing the trailing bracket pair. Both names// "foo" and "foo[]" should be arrays.if (options.hash && key.slice(key.length - 2) !== '[]') {result = serializer(result, key + '[]', option.value);}else {result = serializer(result, key, option.value);}}}// Serialize if no selected options and options.empty is trueif (!isSelectedOptions && options.empty) {result = serializer(result, key, '');}continue;}result = serializer(result, key, val);}// Check for all empty radio buttons and serialize them with key=""if (options.empty) {for (var key in radio_store) {if (!radio_store[key]) {result = serializer(result, key, '');}}}return result;
}function parse_keys(string) {var keys = [];var prefix = /^([^\[\]]*)/;var children = new RegExp(brackets);var match = prefix.exec(string);if (match[1]) {keys.push(match[1]);}while ((match = children.exec(string)) !== null) {keys.push(match[1]);}return keys;
}function hash_assign(result, keys, value) {if (keys.length === 0) {result = value;return result;}var key = keys.shift();var between = key.match(/^\[(.+?)\]$/);if (key === '[]') {result = result || [];if (Array.isArray(result)) {result.push(hash_assign(null, keys, value));}else {// This might be the result of bad name attributes like "[][foo]",// in this case the original `result` object will already be// assigned to an object literal. Rather than coerce the object to// an array, or cause an exception the attribute "_values" is// assigned as an array.result._values = result._values || [];result._values.push(hash_assign(null, keys, value));}return result;}// Key is an attribute name and can be assigned directly.if (!between) {result[key] = hash_assign(result[key], keys, value);}else {var string = between[1];// +var converts the variable into a number// better than parseInt because it doesn't truncate away trailing// letters and actually fails if whole thing is not a numbervar index = +string;// If the characters between the brackets is not a number it is an// attribute name and can be assigned directly.if (isNaN(index)) {result = result || {};result[string] = hash_assign(result[string], keys, value);}else {result = result || [];result[index] = hash_assign(result[index], keys, value);}}return result;
}// Object/hash encoding serializer.
function hash_serializer(result, key, value) {var matches = key.match(brackets);// Has brackets? Use the recursive assignment function to walk the keys,// construct any missing objects in the result tree and make the assignment// at the end of the chain.if (matches) {var keys = parse_keys(key);hash_assign(result, keys, value);}else {// Non bracket notation can make assignments directly.var existing = result[key];// If the value has been assigned already (for instance when a radio and// a checkbox have the same name attribute) convert the previous value// into an array before pushing into it.//// NOTE: If this requirement were removed all hash creation and// assignment could go through `hash_assign`.if (existing) {if (!Array.isArray(existing)) {result[key] = [ existing ];}result[key].push(value);}else {result[key] = value;}}return result;
}// urlform encoding serializer
function str_serialize(result, key, value) {// encode newlines as \r\n cause the html spec says sovalue = value.replace(/(\r)?\n/g, '\r\n');value = encodeURIComponent(value);// spaces should be '+' rather than '%20'.value = value.replace(/%20/g, '+');return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + value;
}module.exports = serialize;

五、原库获取地址

form-serialize - npm

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/89530.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/89530.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vc配置使用预编译

预编译原理 stdafx.h中加入系统文件&#xff0c;减少cpp中对这些文件的解析&#xff0c;提高速度 stdafx.h 会把编译的文件生成pch&#xff0c;后续解析头文件直接调用pch里面的数据 配置 新建stdafx.h和stdafx.cpp文件 配置stdafx.cpp文件为/Yc 创建预编译文件整个项目设置/Yc…

反射机制的登录系统

一、实体层&#xff08;po层&#xff09; //UserInfo package com.hugeyurt.po;import java.sql.ResultSet; import java.sql.SQLException;public class UserInfo {private String userID;private String name;private int count;private Long errorTime;private String pwd;p…

装饰器模式及优化

装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其结构。这种模式创建了一个装饰器类&#xff0c;用来包装原有的类&#xff0c;并在保持类方法签名完整性的前提下&#xff…

共指消解技术全解析:从语言学规则到深度学习(附论文精读)

精读威斯康星大学综述《Coreference Resolution: A Survey》&#xff0c;揭秘NLP中"实体链接"的核心技术一、什么是共指消解&#xff1f;为什么它是NLP的基石&#xff1f;共指消解(Coreference Resolution) 旨在识别文本中指向同一实体的不同表述。例如&#xff1a;t…

git配置git commit -m “fix 11,22: 修改bugid为11,22“

文章目录前言一、报错提示二、实现1.commitlint.config.js规范配置2. **修改正则表达式**&#xff1a;3. **移除 scope-case 规则**&#xff1a;4. **增强自定义规则逻辑**&#xff1a;测试结果&#xff1a;正则表达式详解&#xff1a;前言 提示&#xff1a;正常的配置git规范…

nastools继任者?极空间部署影视自动化订阅系统『MediaMaster』

nastools继任者&#xff1f;极空间部署影视自动化订阅系统『MediaMaster』 哈喽小伙伴们好&#xff0c;我是Stark-C~ 对于我们NAS玩家来说&#xff0c;观影总是大家绕不开的一个执念&#xff0c;并且为观影的折腾大家也都是乐此不疲~ 曾经有一个非常绝绝子的观影神器摆在我们…

题解:CF1690G Count the Trains

思路&#xff1a; 首先我们可以理清一下各种情况&#xff1a;1&#xff09;m可能为02&#xff09;一次操作时&#xff0c;只需要考虑每节火车的车头。3&#xff09;当一节火车的速度降低时&#xff0c;只会影响它及它后面的车厢当m0时&#xff0c;我们可以记录上一节车头的速度…

CCF编程能力等级认证GESP—C++3级—20250628

CCF编程能力等级认证GESP—C3级—20250628单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)奇偶校验分糖果单选题&#xff08;每题 2 分&#xff0c;共 30 分…

2G和3G网络关闭/退网状态(截止2025年7月)

从能打语音电话的2G&#xff0c;到能发彩信、聊QQ的3G&#xff0c;这两项陪伴了我们数十年的通信技术&#xff0c;正在悄然退出历史舞台。近日&#xff0c;全球移动供应商协会&#xff08;GSA&#xff09;发布的《2025年7月2G和3G网络关闭报告》显示&#xff0c;全球已有超百个…

Day06_C语言网络编程20250718mobus重点

01.思维导图1 什么是 modbus他是一个在工控领域非常好用的通信写 modbus协议本质上是一个 基于 tcp 协议二次封装的一个协议 什么叫做基于tcp二次封装的协议&#xff1a;我们自己写的pack_t(无论静态还是动态)&#xff0c;都是属于二次封装的协议modbus协议是一种 “主从问答式…

比亚迪古德伍德亮相:从技术突破到文化对话

近日&#xff0c;比亚迪携腾势Z9GT、方程豹豹5、腾势D9亮相英国古德伍德速度节——全球最具声望的汽车文化盛典。方程豹豹5搭载全球首个 DMO电驱越野平台&#xff0c;在爬山赛道上展现出媲美性能跑车的动力响应与精准控制&#xff0c;彻底打破“越野必靠大排量燃油机”的西方传…

UniApp TabBar 用户头像方案:绕过原生限制的实践

需求场景&#xff1a; 在 UniApp 项目中&#xff0c;需要将 TabBar 首页项 (index) 的图标替换为当前用户的网络图片&#xff0c;并实现&#xff1a; 放大且圆形显示。点击该图标时&#xff0c;页面滚动回顶部。切换到其他分类时&#xff0c;首页 Tab 项恢复为普通首页图标。 尝…

如何阅读Spring源码

如何阅读Spring源码 简介 最近有许多人问我如何阅读Spring源码&#xff0c;那我便在这给出阅读源码的方法&#xff0c;能够保证本地能够让源码能够运行起来。 Spring 源码环境本地编译 Gradle下载地址 通过网盘分享的文件&#xff1a;gradle-6.4.1-all.zip 链接: https://pan.b…

Excel导出实战:从入门到精通 - 构建专业级数据报表的完整指南

文章目录Excel导出实战&#xff1a;从入门到精通 - 构建专业级数据报表的完整指南引言&#xff1a;ExcelJSFileSaver如何映射到Excel操作一、ExcelJS核心架构解析 - 从文件结构理解1. 工作簿(Workbook)模型 - 相当于整个Excel文件2. 工作表(Worksheet)配置 - 相当于单个工作表设…

PyTorch图像预处理全解析(transforms)

1. 引言在深度学习计算机视觉任务中&#xff0c;数据预处理和数据增强是模型训练的关键步骤&#xff0c;直接影响模型的泛化能力和最终性能表现。PyTorch 提供的 torchvision.transforms 模块&#xff0c;封装了丰富的图像变换方法&#xff0c;能够高效地完成图像标准化、裁剪、…

slam中的eskf观测矩阵推导

在之前的《slam中的eskf推导》一文中&#xff0c;没有写观测矩阵 H 矩阵的过程&#xff0c;现在补上这部分。前置列举几个等下推导需要用到的一些点&#xff1a;平面特征点构造观测矩阵例如在 fastlio 中&#xff0c;是利用平面特征点到拟合平面的距离来构造观测方程&#xff0…

Python_2

逻辑判断 首先得首先&#xff0c;我们想判断一个逻辑的正确与否&#xff0c;一定是需要一个能够表现出逻辑的词 如果我只说一个1 2&#xff0c;那么大家都不知道我在说什么但是如果我说1<2,那么大家就能判断这个语句的正确与否了 下面是几个常用的逻辑词 < 小于>大于&…

Liunx-Lvs配置项目练习

1.实验环境配置Lvs调度器有两块网卡 一块仅主机和一块nat网卡&#xff0c;客户端nat模式&#xff0c;两台服务器为仅主机模式2.集群和分布式简介集群与分布式系统简介集群 (Cluster)集群是指将多台计算机(通常为同构的)通过高速网络连接起来&#xff0c;作为一个整体对外提供服…

T5(Text-to-Text Transfer Transformer) 模型

下面是对 T5&#xff08;Text-to-Text Transfer Transformer&#xff09; 模型的详细介绍&#xff0c;包括其原理、架构、训练方式、优势与局限&#xff0c;以及与其他模型&#xff08;如 BERT、GPT&#xff09;的对比。一、T5 是什么&#xff1f;T5&#xff08;Text-to-Text T…

PostgreSQL技术大讲堂 - 第97讲:PG数据库编码和区域(locale)答疑解惑

PostgreSQL从入门到精通系列课程&#xff0c;近100节PG技术讲解&#xff0c;让你从小白一步步成长为独当一面的PG专业人员&#xff0c;点击这里查看章节内容。 PostgreSQL从入门到精通课程&#xff0c;持续更新&#xff0c;欢迎加入。第97讲&#xff1a;PostgreSQL 数据库编码…