表单操作(Form Actions)
本教程共 50 篇 · 第 47 篇 · 更新于 2026-08-05 · 约 6 分钟阅读
47. 表单操作(Form Actions)
本节目标:学会用 SvelteKit 的 Form Actions 处理表单提交,掌握默认 action、命名 action、表单验证、
use:enhance渐进增强和错误处理。
为什么用 Form Actions
传统做法是写一个 API 端点接收表单数据。但这样有两个问题:禁用 JavaScript 的用户无法提交表单,而且需要手写大量前后端交互代码。
SvelteKit 的 Form Actions 让你直接在 +page.server.js 中定义处理函数,用标准 HTML <form> 提交。不需要 JavaScript 也能工作。
默认 action
最简单的情况,在 +page.server.js 中导出 actions:
// src/routes/login/+page.server.js
/** @satisfies {import('./$types').Actions} */
export const actions = {
default: async (event) => {
// 处理登录逻辑
}
};
页面中放一个 <form method="POST">:
<!-- src/routes/login/+page.svelte -->
<form method="POST">
<label>
邮箱
<input name="email" type="email" />
</label>
<label>
密码
<input name="password" type="password" />
</label>
<button>登录</button>
</form>
点击按钮时,浏览器发送 POST 请求到当前页面的 URL,触发 default action。不需要 JavaScript。
NoteActions 总是使用 POST 请求。GET 请求不应该有副作用。
命名 action
一个页面可以有多个 action。用命名 action 区分:
// src/routes/login/+page.server.js
/** @satisfies {import('./$types').Actions} */
export const actions = {
login: async ({ cookies, request }) => {
// 登录逻辑
},
register: async ({ cookies, request }) => {
// 注册逻辑
}
};
表单用 action 属性指定调用哪个:
<form method="POST" action="?/login">
<!-- 登录表单 -->
<button>登录</button>
</form>
<form method="POST" action="?/register">
<!-- 注册表单 -->
<button>注册</button>
</form>
也可以用一个表单,用 formaction 在按钮上切换:
<form method="POST" action="?/login">
<input name="email" type="email" />
<input name="password" type="password" />
<button>登录</button>
<button formaction="?/register">注册</button>
</form>
Tip
action="?/login"中的?/前缀表示当前页面的loginaction。从其他页面提交时用完整路径:action="/login?/login"。
读取表单数据
action 函数接收 RequestEvent,用 request.formData() 读取数据:
export const actions = {
login: async ({ request }) => {
const data = await request.formData();
const email = data.get('email');
const password = data.get('password');
// 处理登录...
return { success: true };
}
};
data.get(name) 返回表单字段值。多个同名字段用 data.getAll(name)。
返回数据给页面
action 返回的数据通过 form prop 传给页面组件:
<!-- src/routes/login/+page.svelte -->
<script>
/** @type {import('./$types').PageProps} */
let { form } = $props();
</script>
{#if form?.success}
<p>登录成功!</p>
{/if}
Note
form数据是临时的——它只在表单提交后的那次渲染中存在。用户刷新页面后form变为null。这和data不同,data在每次导航时都会重新加载。
表单验证:fail()
验证失败时用 fail 返回错误信息和已填写的字段值:
import { fail } from '@sveltejs/kit';
export const actions = {
login: async ({ request }) => {
const data = await request.formData();
const email = data.get('email');
const password = data.get('password');
if (!email) {
return fail(400, { email, missing: true });
}
if (password.length < 6) {
return fail(400, { email, tooShort: true });
}
// 验证通过,执行登录
return { success: true };
}
};
页面上显示错误信息:
<form method="POST" action="?/login">
{#if form?.missing}
<p class="error">请填写邮箱</p>
{/if}
{#if form?.tooShort}
<p class="error">密码至少 6 位</p>
{/if}
<input name="email" type="email" value={form?.email ?? ''} />
<input name="password" type="password" />
<button>登录</button>
</form>
Tip返回已填写的字段值(如
重定向
登录成功后通常要跳转。用 redirect:
import { fail, redirect } from '@sveltejs/kit';
export const actions = {
login: async ({ cookies, request, url }) => {
const data = await request.formData();
// 验证逻辑...
cookies.set('sessionid', sessionId, { path: '/' });
// 跳转到来源页或首页
const redirectTo = url.searchParams.get('redirectTo');
redirect(303, redirectTo || '/');
}
};
redirect 会中断 action 执行并触发跳转,不会渲染当前页面。
use:enhance:渐进增强
默认的表单提交会整页刷新。加上 use:enhance 就变成 AJAX 提交,不刷新页面:
<script>
import { enhance } from '$app/forms';
</script>
<form method="POST" use:enhance>
<!-- 表单内容 -->
</form>
use:enhance 不传参数时,行为模拟浏览器原生提交,但去掉整页刷新。它会:
- 更新
formprop 和page.form - 重置表单
- 成功时重新加载所有数据(
invalidateAll) - 遇到
redirect时执行跳转 - 遇到错误时渲染
+error.svelte - 重置焦点到合适元素
Note
use:enhance只能用于method="POST"且指向+page.server.js中定义的 action 的表单。
自定义 use:enhance
需要更多控制时,传一个回调函数:
<script>
import { enhance } from '$app/forms';
let loading = $state(false);
</script>
<form
method="POST"
use:enhance={({ formElement, formData, action, cancel }) => {
// 提交前:可以取消提交
loading = true;
// cancel() 可以阻止提交
return async ({ result, update }) => {
// 提交后:result 是 ActionResult
loading = false;
// update() 执行默认行为
await update();
};
}}
>
<button disabled={loading}>
{loading ? '提交中...' : '登录'}
</button>
</form>
回调参数:
| 参数 | 说明 |
|---|---|
formElement | 表单 DOM 元素 |
formData | 即将提交的 FormData 对象 |
action | 提交目标 URL |
cancel() | 调用后取消提交 |
submitter | 触发提交的元素 |
返回的回调接收 result(ActionResult)和 update 函数。
action 执行后重新加载 load
action 完成后,页面的 load 函数会重新运行(除非发生重定向或未捕获错误)。这意味着 action 修改的数据会自动反映到页面上:
// src/routes/todos/+page.server.js
export async function load() {
return { todos: await db.getTodos() };
}
export const actions = {
add: async ({ request }) => {
const data = await request.formData();
await db.addTodo(data.get('text'));
// load 会重新运行,页面自动更新
}
};
本节回顾
+page.server.js中导出actions对象,用标准 HTML<form method="POST">提交- 默认 action 用
default,命名 action 用action="?/name"调用 request.formData()读取表单数据,返回值通过formprop 传给页面fail()返回验证错误和已填字段值redirect()处理成功后的跳转use:enhance让表单变 AJAX 提交,不刷新页面- 自定义
use:enhance回调可以显示加载状态、取消提交等 - action 完成后页面的
load函数自动重新运行