在前端开发中,表单是用户与系统交互的核心载体,很多时候我们需要在表单提交后,将用户输入的数据整理成结构清晰、符合后端要求的JSON对象,避免数据格式混乱带来的对接问题。jQuery作为常用的前端库,提供了便捷的DOM操作能力,结合合理的逻辑处理就能实现这一目标。

核心处理思路
要实现表单数据到结构化JSON的转换,核心逻辑可以分为三步:首先获取表单内所有需要提交的表单元素,然后提取每个元素的名称和对应的值,最后根据名称的规则处理嵌套结构、数组等特殊情况,组装成最终的JSON对象。
基础表单元素取值
常见的表单元素包括<input>、<select>、<textarea>,不同类型的元素取值方式略有区别,我们可以通过统一的逻辑处理:
// 获取单个表单元素的值
function getFormElementValue(element) {
const type = element.attr('type');
const tagName = element.prop('tagName').toLowerCase();
// 处理checkbox类型
if (type === 'checkbox') {
return element.is(':checked') ? element.val() : null;
}
// 处理radio类型
if (type === 'radio') {
if (element.is(':checked')) {
return element.val();
}
return undefined;
}
// 处理select多选
if (tagName === 'select' && element.prop('multiple')) {
return element.val() || [];
}
// 其他类型直接取值
return element.val();
}
结构化名称规则设计
要实现嵌套的JSON结构,我们需要给表单元素的name属性定义规则,比如用点号表示层级,用方括号表示数组:
user.name对应 JSON 中的{ user: { name: 'xxx' } }hobby[]对应 JSON 中的{ hobby: ['xxx', 'yyy'] }address[0].city对应 JSON 中的{ address: [{ city: 'xxx' }] }
完整实现代码
结合上述思路,我们可以封装一个通用的转换函数,在表单提交时调用:
function formToStructuredJson(formSelector) {
const formData = {};
// 获取表单内所有可提交的表单元素
const formElements = $(formSelector).find('input, select, textarea').not('[type="button"], [type="submit"], [type="reset"]');
formElements.each(function() {
const element = $(this);
const name = element.attr('name');
if (!name) return; // 没有name属性的元素跳过
let value = getFormElementValue(element);
// 处理radio未选中的情况
if (value === undefined) return;
// 处理checkbox未选中的情况
if (value === null) return;
// 解析name的层级结构
const nameParts = parseName(name);
setNestedValue(formData, nameParts, value);
});
return formData;
}
// 解析name属性为层级数组
function parseName(name) {
const parts = [];
const reg = /([^.[]]+)|([])/g;
let match;
while ((match = reg.exec(name)) !== null) {
if (match[1]) {
parts.push(match[1]);
} else if (match[2]) {
parts.push('[]');
}
}
return parts;
}
// 设置嵌套对象的值
function setNestedValue(obj, parts, value) {
let current = obj;
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
const isLast = i === parts.length - 1;
if (part === '[]') {
// 处理数组
if (!Array.isArray(current)) {
// 如果当前不是数组,初始化为数组
// 这里需要根据上下文处理,实际场景中可以根据前一个part的类型调整
// 简化逻辑:直接初始化为空数组
current = [];
}
if (isLast) {
current.push(value);
} else {
// 数组内嵌套对象的情况,简化处理逻辑
const nextPart = parts[i + 1];
const newItem = {};
current.push(newItem);
current = newItem;
i++; // 跳过下一个part,因为已经处理到数组内的对象
}
} else {
if (isLast) {
current[part] = value;
} else {
if (!current[part]) {
// 判断下一个part是否是数组
const nextPart = parts[i + 1];
current[part] = nextPart === '[]' ? [] : {};
}
current = current[part];
}
}
}
}
// 表单提交事件绑定
$(function() {
$('#submitForm').on('submit', function(e) {
e.preventDefault();
const jsonData = formToStructuredJson(this);
console.log('转换后的JSON数据:', jsonData);
// 这里可以发送AJAX请求提交数据
// $.ajax({
// url: '/api/submit',
// type: 'POST',
// contentType: 'application/json',
// data: JSON.stringify(jsonData),
// success: function(res) {
// console.log('提交成功', res);
// }
// });
return false;
});
});
示例表单与效果演示
我们定义一个包含嵌套结构、数组的表单,测试转换效果:
<form id="submitForm">
<h3>用户信息</h3>
<p>用户名:<input type="text" name="user.name" value="张三"></p>
<p>年龄:<input type="number" name="user.age" value="25"></p>
<h3>兴趣爱好</h3>
<p>
<input type="checkbox" name="hobby[]" value="篮球" checked>篮球
<input type="checkbox" name="hobby[]" value="足球">足球
<input type="checkbox" name="hobby[]" value="羽毛球" checked>羽毛球
</p>
<h3>收货地址</h3>
<p>城市:<input type="text" name="address[0].city" value="北京"></p>
<p>街道:<input type="text" name="address[0].street" value="朝阳路"></p>
<p><button type="submit">提交表单</button></p>
</form>
上述表单提交后,转换得到的JSON对象结构如下:
{
"user": {
"name": "张三",
"age": "25"
},
"hobby": ["篮球", "羽毛球"],
"address": [
{
"city": "北京",
"street": "朝阳路"
}
]
}
注意事项
- 如果表单中包含文件上传元素,需要额外处理
FormData,上述方案仅适用于非文件类型的表单数据 - 对于复杂的嵌套场景,可以根据实际需求调整
parseName和setNestedValue的逻辑 - 转换后的JSON值默认都是字符串类型,如果需要转换数字、布尔等类型,可以在
getFormElementValue中增加类型判断逻辑