You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 11:22:52