模块化表单
Modular Forms 是一个基于 Qwik 构建的类型安全表单库。它的无头设计使您可以完全控制表单的视觉外观。该库负责状态管理和输入验证。
要开始使用,请安装 npm 包:
npm install @modular-forms/qwik
定义表单
在开始创建表单之前,您需要定义字段的结构和数据类型。除了字符串,Modular Forms 还可以处理布尔值、数字、文件、日期、对象和数组。
type LoginForm = {
email: string;
password: string;
};
由于 Modular Forms 支持 Valibot 和 Zod 进行输入验证,您可以选择从模式派生类型定义。
import { email, type Input, minLength, object, string } from 'valibot';
const LoginSchema = object({
email: string([
minLength(1, '请输入您的电子邮件。'),
email('电子邮件地址格式不正确。'),
]),
password: string([
minLength(1, '请输入您的密码。'),
minLength(8, '您的密码必须包含 8 个或更多字符。'),
]),
});
type LoginForm = Input<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">登录</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) => {
// 在服务器上运行
}, valiForm$(LoginSchema));
export default component$(() => {
const [loginForm, { Form, Field }] = useForm<LoginForm>({
loader: useFormLoader(),
action: useFormAction(),
validate: valiForm$(LoginSchema),
});
const handleSubmit = $<SubmitHandler<LoginForm>>((values, event) => {
// 在客户端上运行
});
return (
<Form onSubmit$={handleSubmit}>
…
</Form>
);
});
最终表单
现在,我们将所有构建块组合在一起,就可以得到一个可工作的登录表单。下面是组装的代码,并可以在附带的沙箱中尝试它。
// @ts-nocheck
/* eslint-disable @typescript-eslint/no-unused-vars */
import { $, component$ } 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 { email, type Input, minLength, object, string } from 'valibot';
const LoginSchema = object({
email: string([
minLength(1, 'Please enter your email.'),
email('The email address is badly formatted.'),
]),
password: string([
minLength(1, 'Please enter your password.'),
minLength(8, 'Your password must have 8 characters or more.'),
]),
});
type LoginForm = Input<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: 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 上得到您的星星!