首页 / Svelte 5 入门教程 / 表单操作(Form Actions)

Svelte 5 入门教程

表单操作(Form Actions)

本教程共 50 篇 · 第 47 篇 · 更新于 2026-08-05 · 约 6 分钟阅读

SvelteSvelteKit表单Form Actionsuse:enhance

本节目标:学会用 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。

Note

Actions 总是使用 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" 中的 ?/ 前缀表示当前页面的 login action。从其他页面提交时用完整路径: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

返回已填写的字段值(如 email),让用户不用重新输入。但不要返回密码等敏感字段。

重定向

登录成功后通常要跳转。用 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 不传参数时,行为模拟浏览器原生提交,但去掉整页刷新。它会:

  • 更新 form prop 和 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触发提交的元素

返回的回调接收 resultActionResult)和 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() 读取表单数据,返回值通过 form prop 传给页面
  • fail() 返回验证错误和已填字段值
  • redirect() 处理成功后的跳转
  • use:enhance 让表单变 AJAX 提交,不刷新页面
  • 自定义 use:enhance 回调可以显示加载状态、取消提交等
  • action 完成后页面的 load 函数自动重新运行