如何规整提交含重复字段/组件的表单并获取结构化数据?
问题描述
我有一个Svelte组件TrackForm.svelte,包含两个输入字段,代码如下:
<script> export let componentID; console.log("component iD", componentID) </script> <div> <div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6"> <div class="sm:col-span-3"> <label class="label"> <span class="label-text text-lg">Title</span> </label> <input type="text" name="track-title[][{componentID}]" class="input input-bordered input-lg w-full"> </div> <div class="sm:col-span-1"> <label class="label"> <span class="label-text text-lg">Duration</span> </label> <input type="text" name="track-duration[][{componentID}]" class="input input-bordered input-lg w-full"> </div> </div> </div>
在+page.svelte中我引入了多份该组件,用于提交多条轨道数据:
<script> import TrackForm from "../../components/forms/TrackForm.svelte"; </script> <form method="POST"> <TrackForm componentID="1" /> <br/> <hr> <br/> <TrackForm componentID="2" /> <button type="submit" class="btn-primary btn-wide btn-info mt-10">Save</button> </form>
后端+page.server.js的action仅打印提交的数据:
export const actions = { default: async ({ request }) => { const data = Object.fromEntries(await request.formData()); console.log("data:", data); return {} } }
提交后得到的数据格式是:
data: { 'track-title[][1]': 'aaaaa', 'track-duration[][1]': '111', 'track-title[][2]': 'vbbb', 'track-duration[][2]': '2222' }
我希望能自动得到更规整的数组格式,比如:
[ { "track-title": 'aaaaa', "track-duration": '111' }, { "track-title": 'vbbb', "track-duration": '2222' } ]
想知道有没有办法实现,或者相关可用的库。
解决方案
方法一:调整表单字段name属性,让表单自动分组
直接修改TrackForm组件中输入框的name属性格式,利用HTML表单的数组分组特性,无需额外的componentID就能自动把同一条轨道的字段归为一组:
修改TrackForm.svelte中的输入框name:
<input type="text" name="tracks[][track-title]" class="input input-bordered input-lg w-full"> <!-- 替换原有的 track-title[][{componentID}] --> <input type="text" name="tracks[][track-duration]" class="input input-bordered input-lg w-full"> <!-- 替换原有的 track-duration[][{componentID}] -->
提交后,后端解析时会自动把同一份TrackForm的字段归到同一个数组元素,后续只需用工具解析成对象数组即可。
方法二:后端手动解析现有格式
如果不想修改前端代码,可在后端手动处理返回的数据,按componentID分组:
修改+page.server.js的action:
export const actions = { default: async ({ request }) => { const formData = await request.formData(); const data = Object.fromEntries(formData); const grouped = {}; // 遍历所有字段,按ID分组 for (const [key, value] of Object.entries(data)) { const match = key.match(/\[(\d+)\]$/); if (match) { const id = match[1]; const fieldName = key.replace(/\[\]\[\d+\]$/, ''); if (!grouped[id]) grouped[id] = {}; grouped[id][fieldName] = value; } } // 转成数组并按ID排序 const result = Object.values(grouped).sort((a, b) => { const idA = Object.keys(data).find(k => k.includes(a['track-title'])).match(/\[(\d+)\]$/)[1]; const idB = Object.keys(data).find(k => k.includes(b['track-title'])).match(/\[(\d+)\]$/)[1]; return idA - idB; }); console.log("规整后的数据:", result); return {} } }
方法三:使用表单解析库
可以用专门的表单数据解析库简化处理,比如qs:
首先安装qs:
npm install qs
然后在后端使用:
import qs from 'qs'; export const actions = { default: async ({ request }) => { const formData = await request.formData(); const params = new URLSearchParams(formData).toString(); // 解析表单参数 const parsed = qs.parse(params, { arrayFormat: 'brackets' }); // 合并成目标格式的数组 const result = parsed['track-title'].map((title, index) => ({ 'track-title': title, 'track-duration': parsed['track-duration'][index] })); console.log("规整后的数据:", result); return {} } }
内容的提问来源于stack exchange,提问作者MrCujo
相关产品推荐
相关产品推荐

