模块化表单
模块化表单 是一个基于 Qwik 原生构建的类型安全表单库。无头设计让您可以完全控制表单的视觉外观。该库负责状态管理和输入验证。
要开始使用,请安装 npm 包
npm install @modular-forms/qwik
定义您的表单
在开始创建表单之前,您需要定义字段的结构和数据类型。除了字符串之外,模块化表单还可以处理布尔值、数字、文件、日期、对象和数组。
type LoginForm = {
email: string;
password: string;
};
由于模块化表单支持 Valibot 和 Zod 进行输入验证,因此您可以选择从模式中推导出类型定义。
import * as v from 'valibot';
const LoginSchema = v.object({
email: v.pipe(
v.string(),
v.nonEmpty('Please enter your email.'),
v.email('The email address is badly formatted.'),
),
password: v.pipe(
v.string(),
v.nonEmpty('Please enter your password.'),
v.minLength(8, 'Your password must have 8 characters or more.'),
),
});
type LoginForm = v.InferInput<typeof LoginSchema>;
如果您想知道为什么本指南更倾向于使用 Valibot 而不是 Zod,我建议您阅读这篇 公告文章。
设置初始值
创建类型定义后,继续设置表单的初始值。为此,请创建一个 routeLoader$
并使用您之前创建的类型作为泛型。
export const useFormLoader = routeLoader$<InitialValues<LoginForm>>(() => ({
email: '',
password: '',
}));
在 routeLoader$
中,您可以使用空字符串,也可以查询并传递来自数据库的值。根据传递的对象,表单的存储将被初始化,使 Qwik 能够可靠地在服务器上预渲染您的网站。初始值也用于稍后检查用户输入后字段的值是否已更改。
创建表单
要创建表单,请使用 useForm
钩子。它返回表单的存储和一个包含 Form
、Field
和 FieldArray
组件的对象。作为参数,您将包含之前创建的加载器的对象传递给 useForm
。
export default component$(() => {
const [loginForm, { Form, Field, FieldArray }] = useForm<LoginForm>({
loader: useFormLoader(),
});
});
您可以使用 loginForm
对象访问表单的当前状态。此外,您可以将其传递给库提供的各种方法,例如 reset
或 setValue
,以对状态进行手动更改。
在组件的 JSX 部分,您继续使用 Form
组件。它包含表单的字段,并且您可以通过其属性定义表单提交时会发生什么。
export default component$(() => {
const [loginForm, { Form, Field, FieldArray }] = useForm<LoginForm>({
loader: useFormLoader(),
});
return <Form>…</Form>;
});
添加表单字段
现在您可以继续添加表单的字段。使用 Field
和 FieldArray
组件,您可以注册一个字段或字段数组。这两个组件都是无头的,并为您提供对其当前状态的直接访问权限。渲染道具的第二个参数必须传递给 <input />
、<select />
或 <textarea />
元素,以将其连接到您的表单。
<Form>
<Field name="email">
{(field, props) => (
<input {...props} type="email" value={field.value} />
)}
</Field>
<Field name="password">
{(field, props) => (
<input {...props} type="password" value={field.value} />
)}
</Field>
<button type="submit">Login</button>
</Form>
这种 API 设计导致了一个完全类型安全的表单。此外,它让您可以完全控制用户界面。您可以开发自己的 TextInput
组件或连接预构建的组件库。
输入验证
模块化表单的核心功能之一是输入验证。您可以为此使用 Valibot 或 Zod 模式,也可以使用我们的内部验证函数。为了使本指南保持简单,我们使用之前创建的 Valibot 模式并将其传递给 useForm
钩子。
valiForm$
是一个适配器,它将 Valibot 的错误消息转换为模块化表单期望的格式。对于 Zod,请使用zodForm$
代替。
const [loginForm, { Form, Field, FieldArray }] = useForm<LoginForm>({
loader: useFormLoader(),
validate: valiForm$(LoginSchema),
});
现在您只需要在发生错误时显示字段的错误消息即可。
<Field name="email">
{(field, props) => (
<div>
<input {...props} type="email" value={field.value} />
{field.error && <div>{field.error}</div>}
</div>
)}
</Field>
处理提交
在最后一步中,您只需要在提交表单时通过函数访问值,以进一步处理和使用它们。您可以为此使用 formAction$
或 Form
组件的 onSubmit$
属性。
export const useFormAction = formAction$<LoginForm>((values) => {
// Runs on server
}, valiForm$(LoginSchema));
export default component$(() => {
const [loginForm, { Form, Field }] = useForm<LoginForm>({
loader: useFormLoader(),
action: useFormAction(),
validate: valiForm$(LoginSchema),
});
const handleSubmit = $<SubmitHandler<LoginForm>>((values, event) => {
// Runs on client
});
return (
<Form onSubmit$={handleSubmit}>
…
</Form>
);
});
最终表单
如果我们现在将所有构建块组合在一起,我们将得到一个可工作的登录表单。您可以在下面看到组装后的代码,并在附带的沙盒中试用它。
// @ts-nocheck
/* eslint-disable @typescript-eslint/no-unused-vars */
import { $, component$, type QRL } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
import type { InitialValues, SubmitHandler } from '@modular-forms/qwik';
import { formAction$, useForm, valiForm$ } from '@modular-forms/qwik';
import * as v from 'valibot';
const LoginSchema = v.object({
email: v.pipe(
v.string(),
v.nonEmpty('Please enter your email.'),
v.email('The email address is badly formatted.'),
),
password: v.pipe(
v.string(),
v.nonEmpty('Please enter your password.'),
v.minLength(8, 'Your password must have 8 characters or more.'),
),
});
type LoginForm = v.InferInput<typeof LoginSchema>;
export const useFormLoader = routeLoader$<InitialValues<LoginForm>>(() => ({
email: '',
password: '',
}));
export const useFormAction = formAction$<LoginForm>((values) => {
// Runs on server
}, valiForm$(LoginSchema));
export default component$(() => {
const [loginForm, { Form, Field }] = useForm<LoginForm>({
loader: useFormLoader(),
action: useFormAction(),
validate: valiForm$(LoginSchema),
});
const handleSubmit: QRL<SubmitHandler<LoginForm>> = $((values, event) => {
// Runs on client
console.log(values);
});
return (
<Form onSubmit$={handleSubmit}>
<Field name="email">
{(field, props) => (
<div>
<input {...props} type="email" value={field.value} />
{field.error && <div>{field.error}</div>}
</div>
)}
</Field>
<Field name="password">
{(field, props) => (
<div>
<input {...props} type="password" value={field.value} />
{field.error && <div>{field.error}</div>}
</div>
)}
</Field>
<button type="submit">Login</button>
</Form>
);
});
总结
您已经学习了模块化表单的基础知识,并准备创建您的第一个简单表单。有关更多信息和详细信息,您可以在我们的网站上找到更多指南和 API 参考:modularforms.dev
您是否喜欢模块化表单?如果您在 GitHub 上给我们一颗星,我们将不胜荣幸!