SvelteKit中如何通过Form Actions提交多页表单?
问题原因
你的代码里,表单提交时只有当前页面的输入框存在于DOM中,浏览器只会收集当前存在的表单控件值,所以前两页的name和email不会被包含在FormData里,导致服务器拿到的都是null。
解决方案(基于Form Actions实现)
方案一:隐藏字段存储已填数据
通过隐藏字段持久化所有页的表单值,切换页面时同步更新隐藏字段,提交时所有数据都会被发送到服务器。
修改后的+page.svelte代码:
<script lang="ts"> import {enhance} from "$app/forms"; let page: number = 1; // 定义变量存储所有表单值 let name = 'John Doe'; let email = ''; let password = ''; const nextPage = () => { page++; } const prevPage = () => { page--; } </script> <form method="POST" use:enhance> <!-- 隐藏字段,始终存在于表单中,存储所有数据 --> <input type="hidden" name="name" value={name}> <input type="hidden" name="email" value={email}> <input type="hidden" name="password" value={password}> {#if page === 1} <label for="name">Name</label> <input type="text" id="name" bind:value={name}> {:else if page === 2} <label for="email">Email</label> <input type="email" id="email" bind:value={email}> {:else if page === 3} <label for="password">Password</label> <input type="password" id="password" bind:value={password}> <button type="submit">Register</button> {:else} <p>Thank you for registering!</p> {/if} <button type="button" on:click={prevPage} disabled={page === 1}>Previous</button> <button type="button" on:click={nextPage} disabled={page === 4}>Next</button> </form>
+page.server.ts无需修改,提交后就能拿到完整的name、email、password值。
方案二:服务器端会话暂存数据(更安全)
每一页点击「Next」时提交到服务器,将数据暂存在会话中,最后一页提交时汇总所有数据。适合敏感数据场景,避免客户端存储敏感信息。
修改+page.svelte:
<script lang="ts"> import {enhance} from "$app/forms"; import {page} from "$app/stores"; // 从服务器加载已暂存的表单数据和当前页码 let currentPage = $page.data.currentPage || 1; let name = $page.data.name || 'John Doe'; let email = $page.data.email || ''; let password = ''; </script> <form method="POST" use:enhance> <input type="hidden" name="step" value={currentPage}> {#if currentPage === 1} <label for="name">Name</label> <input type="text" id="name" name="name" value={name}> <button type="submit">Next</button> {:else if currentPage === 2} <label for="email">Email</label> <input type="email" id="email" name="email" value={email}> <button type="submit">Next</button> <button type="button" on:click={() => currentPage--}>Previous</button> {:else if currentPage === 3} <label for="password">Password</label> <input type="password" id="password" name="password"> <button type="submit">Register</button> <button type="button" on:click={() => currentPage--}>Previous</button> {:else} <p>Thank you for registering!</p> {/if} </form>
修改+page.server.ts(需配置SvelteKit会话):
import type { Actions, PageServerLoad } from './$types'; import { fail, redirect } from '@sveltejs/kit'; export const load: PageServerLoad = async ({ locals }) => { // 从会话中读取暂存的表单数据 return { currentPage: locals.session.form?.currentPage || 1, name: locals.session.form?.name || '', email: locals.session.form?.email || '' }; }; export const actions: Actions = { default: async ({ request, locals }) => { const formData = await request.formData(); const step = parseInt(formData.get('step') as string); const sessionForm = locals.session.form || {}; switch (step) { case 1: const name = formData.get('name'); if (!name) return fail(400, { error: '请填写姓名' }); // 暂存姓名到会话 locals.session.form = { ...sessionForm, name, currentPage: 2 }; await locals.session.save(); return { currentPage: 2, name }; case 2: const email = formData.get('email'); if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email as string)) { return fail(400, { error: '请填写有效的邮箱' }); } // 暂存邮箱到会话 locals.session.form = { ...sessionForm, email, currentPage: 3 }; await locals.session.save(); return { currentPage: 3, email }; case 3: const password = formData.get('password'); if (!password || (password as string).length < 6) { return fail(400, { error: '密码长度不能少于6位' }); } // 汇总所有数据 const fullData = { name: sessionForm.name, email: sessionForm.email, password }; console.log(fullData); // 此处可执行数据库存储等操作 // 清理会话中的表单数据 delete locals.session.form; await locals.session.save(); throw redirect(303, '/'); default: return fail(400, { error: '无效的步骤' }); } } };
注:此方案需要配置SvelteKit会话支持,比如使用适配自带会话功能的适配器(如Vercel适配器)或第三方会话库。
内容的提问来源于stack exchange,提问作者tinykishore
相关产品推荐
相关产品推荐

