跳转到内容

表单与表格 Hook

功能完备的表单 Hook,支持自动保存、验证和路由自动推导。

const form = useForm({ resource: 'posts', action: 'create' });

在页面 /#/posts/edit/5 上,只需调用:

const form = useForm();
// 自动推导:resource='posts', action='edit', id='5'
选项类型默认值说明
resourcestring?自动资源名称(从路由自动推导)
action'create' | 'edit' | 'clone'自动表单动作
idstring | number自动编辑/克隆的记录 ID
redirect'list' | 'edit' | 'show' | false'list'提交后跳转位置
validate(values) => errors | null—客户端验证
autoSave{ enabled, debounce? }—自动保存
mutationModeMutationMode'pessimistic'变更策略
undoableTimeoutnumber5000撤销超时(毫秒)
const {
// 表单值(唯一数据源)
values, // TVariables(响应式)
setFieldValue, // (field, value, opts?) => void
setValues, // (newValues, opts?) => void
// 脏状态(Tainted)
tainted, // Record<string, boolean>(响应式)
isTainted, // (field?) => boolean
// 错误
errors, // Record<string, string>(响应式)
setFieldError, // (field, message) => void
clearFieldError, // (field) => void
clearErrors, // () => void
validateField, // (field) => string | null
// 提交
submit, // (overrides?) => Promise<void> — 验证 + 提交
reset, // () => void — 重置为初始值
// 状态
loading, // boolean — 查询加载中(编辑/克隆)
submitting, // boolean — 变更进行中
resource, // string
action, // 'create' | 'edit' | 'clone'
id, // string | number | undefined
setId, // (newId) => void
// 自动保存
triggerAutoSave, // () => void
autoSave, // { status, data, error }
// 原始查询/变更(逃生舱)
query, // TanStack 查询(编辑/克隆模式)
mutation, // TanStack 变更
} = useForm();

当 DataProvider 抛出 HttpError 时,验证错误会自动映射到表单字段:

// 在 DataProvider 中:
throw new HttpError('验证失败', 422, {
email: ['邮箱为必填项'],
name: '名称太短',
});
// → form.errors = { email: '邮箱为必填项', name: '名称太短' }

多步骤向导表单,支持步骤导航和逐步验证。

<script lang="ts">
import { useStepsForm } from '@svadmin/core';
const {
steps: { currentStep, gotoStep, canGoNext, canGoPrev, nextStep, prevStep, totalSteps },
...formProps
} = useStepsForm({
resource: 'products',
action: 'create',
stepsCount: 3,
validate: (values, step) => {
if (step === 0 && !values.name) return { name: '必填' };
if (step === 1 && !values.price) return { price: '必填' };
return null;
},
});
</script>
{#if currentStep === 0}
<input bind:value={name} />
{:else if currentStep === 1}
<input bind:value={price} type="number" />
{:else}
<p>确认并提交</p>
{/if}
<button onclick={prevStep} disabled={!canGoPrev}>上一步</button>
<button onclick={nextStep} disabled={!canGoNext}>下一步</button>

在 useForm 返回值基础上增加 steps 对象:

属性类型说明
currentStepnumber当前步骤索引(从 0 开始)
totalStepsnumber总步骤数
gotoStep(step) => void跳转到指定步骤
nextStep() => void前往下一步(会验证当前步骤)
prevStep() => void返回上一步
canGoNextboolean是否可以前进
canGoPrevboolean是否可以后退

弹窗表单 — 同时管理打开/关闭状态和表单生命周期。

const { modal, ...formProps } = useModalForm({ resource: 'posts' });
// modal.show(id?) — 打开弹窗(传入 id 表示编辑)
// modal.close() — 关闭弹窗
// modal.visible — boolean
<button onclick={() => modal.show()}>创建文章</button>
<button onclick={() => modal.show(post.id)}>编辑</button>
{#if modal.visible}
<dialog open>
<form onsubmit|preventDefault={() => formProps.submit()}>
<!-- 表单字段 -->
<button type="submit">保存</button>
<button type="button" onclick={modal.close}>取消</button>
</form>
</dialog>
{/if}

与 useModalForm 完全相同的 API,用于抽屉/侧滑面板:

const { drawer, ...formProps } = useDrawerForm({ resource: 'posts' });
// drawer.show(id?) / drawer.close() / drawer.visible

表格 Hook,支持分页、排序、过滤和 URL 同步。

const table = useTable({ resource: 'posts' });
const table = useTable(); // 从路由自动推导资源名
选项类型默认值
resourcestring?自动
paginationPagination{ current: 1, pageSize: 10 }
sortersSort[][]
filtersFilter[][]
syncWithLocationbooleanfalse
const {
query, // TanStack 查询结果
pagination, // { current, pageSize } — 响应式 $state
sorters, // Sort[] — 响应式 $state
filters, // Filter[] — 响应式 $state
setCurrent, // (page) => void
setPageSize, // (size) => void
setSorters, // (sorters) => void
setFilters, // (filters) => void
} = useTable();