表单仍然是用户与网络交互方式的一个组成部分。在处理表单时,我们必须处理跟踪用户输入,验证和显示错误,以及处理表单的提交。
在这篇文章中,我们将学习输入绑定在Svelte中是如何工作的,如何用Yup验证表单,以及svelte-forms-lib ,使管理表单更容易。我们还将建立一个样本表单,并使用这些工具对其进行验证,以展示在Svelte中建立和验证表单时的多种选择。
了解Svelte的输入绑定
我们需要一种方法来跟踪和存储用户键入时的输入字段的值。Svelte提供了两个指令来实现这一点:on:input 和bind 。
on:input
每当有输入事件发生时,这个事件监听器就会被调用。
<script>
let email = "";
const handleInput = (e) => {
email = e.target.value;
};
</script>
<input type="email" name="email" on:input={handleInput} />
<p>{email}</p>
在上面的代码中,我们定义了一个handleInput ,并将其传递给电子邮件输入栏。每当用户输入时,email 变量就会被更新为该字段的值。
bind:value
bind 指令是在Svelte中追踪表单值的一种更简洁的工作方式。
<input type="email" name="email" bind:value={email} />
我们不需要创建一个handleInput 事件,也不需要为给定表单中的每个输入字段设置event.target.value ,而是由bind 为我们处理,每当我们填写输入时,email 变量就会更新。
在本文中,我们将使用bind 指令来跟踪和存储表单值,因为它是一种更简单的工作方式。
用Yup进行验证
Yup是一个JavaScript对象模式验证器。Yup确保对象中的数据处于我们想要的形式和形状。
import * as yup from 'yup';
let values = {
email: "",
password: "",
confirmPassword: "",
hobby: "",
checkbox: false,
};
const schema = yup.object().shape({
email: yup.string().required("Email is required")
.email("Email is invalid"),
password: yup.string().required("Password is required"),
confirmPassword: yup.string().required("Please confirm your password")
.oneOf([yup.ref("password"), null], "Passwords do not match"),
hobby: yup.string().required("Hobby is required"),
checkbox: yup.bool().required("Checkbox must be accepted")
.oneOf([true], "Checkbox must be accepted"),
});
const validationResult = schema
.validate(values, { abortEarly: false })
.then(() => {
alert(JSON.stringify(values, null, 2));
})
.catch((err) => {
console.log(err.errors);
});
//console.log message
//[ "Email is invalid", "Passwords do not match", "Hobby is required", "Che//ckbox must be accepted" ]
在schema ,我们定义了我们希望我们的表单值的数据是什么样子。这可以确保发送到服务器的数据是有效的。
我们在Yup中使用其validate 方法来验证对象。我们可以在我们定义的任何模式上调用这个方法。
创建一个配置文件表单
现在我们明白了表单绑定在Svelte中是如何工作的,以及Yup是如何验证对象值的,让我们来设置一个配置文件表单的样本并对其进行验证。
<script>
import schema from './schema';
let values = {
//store form data that will then be validated
};
const handleSubmit = () => {
//validate form and submit data
};
</script>
<div class="container">
<h1>Profile Form</h1>
<form on:submit|preventDefault={handleSubmit}>
<div>
<input type="text" name="email" bind:value={values.email}
placeholder="Email"
/>
</div>
<div>
<input type="password" name="password" bind:value={values.password}
placeholder="Password"
/>
</div>
<div>
<input type="password" name="confirmPassword"
bind:value={values.confirmPassword}
placeholder="Confirm password"
/>
</div>
<div>
<select name="hobby" bind:value={values.hobby}>
<option value="">Select a hobby</option>
<option value="Eating">Eating</option>
<option value="Reading">Reading</option>
<option value="Sleeping">Sleeping</option>
</select>
</div>
<div>
<label for="checkbox">Check this box</label>
<input name="checkbox" type="checkbox" bind:checked={values.checkbox} />
</div>
</form>
</div>
我们首先建立一个简单的个人资料表格来获取用户的数据。我们把表单字段绑定到一个values 对象。这个对象是我们将存储表单数据的地方。
验证个人资料表格
现在我们已经创建了个人资料表格,我们需要对它进行验证。
与我们将错误记录到控制台时的做法不同,我们要将它们显示给用户看。
<script>
let errors = {};
const handleSubmit = async () => {
try {
await schema.validate(values, { abortEarly: false });
alert(JSON.stringify(values, null, 2));
errors = {};
} catch (err) {
errors = err.inner.reduce((acc, err) => {
return { ...acc, [err.path]: err.message };
}, {});
}
};
</script>
在这个代码块中,我们创建了一个errors 对象,在这里我们将存储从validate 调用得到的错误。然后,我们创建一个异步函数,handleSubmit 。在这里,我们将处理表单的验证和提交。
我们把我们要验证的数据传给这个方法。在这种情况下,我们将验证从表单中收到的values 。
Validate 可以接受第二个参数,一个选项对象。默认情况下,验证会在第一个错误时返回。要获得所有返回的错误,我们必须将abortEarly 设置为false 。
如果没有错误,我们就显示表单的值。如果有,我们就显示错误。然而,在我们显示错误之前,我们必须访问它们。
errors = err.inner.reduce((acc, err) => {
return { ...acc, [err.path]: err.message };
}, {});
为了访问错误,我们在Yup的验证error.inner 数组上循环,并返回一个由字段和它们的错误信息组成的新对象。然后我们用每个相应的输入字段的错误来更新errors 对象。
显示验证错误
现在我们有了保存每个输入字段的错误的errors 对象,我们需要显示它们。
<div>
<input type="email" />
{#if errors.email}
<span class="error">{errors.email}</span>
{/if}
</div>
<div>
<input type="password" />
{#if errors.password}
<span class="error">{errors.password}</span>
{/if}
</div>
<div>
<input type="password" />
{#if errors.confirmPassword}
<span class="error">{errors.confirmPassword}</span>
{/if}
</div>
<div>
<select name="hobby" bind:value={values.hobby}>
<option value="">Select a hobby</option>
<option value="Eating">Eating</option>
<option value="Reading">Reading</option>
<option value="Sleeping">Sleeping</option>
</select>
{#if errors.hobby}
<span class="error">{errors.hobby}</span>
{/if}
</div>
<div>
<input name="checkbox" type="checkbox" bind:checked={values.checkbox} />
{#if errors.checkbox}
<span class="error">{errors.checkbox}</span>
{/if}
</div>
我们设置了一个if 块来处理显示错误。如果一个特定字段存在错误,我们就显示该字段的错误。这个CodeSandbox链接包含了本节的代码。
使用验证svelte-forms-lib
Svelte forms lib是一个受Formik启发的库,用于在Svelte项目中轻松构建表单。
你可以通过以下方式安装svelte-forms-lib 。
npm i svelte-forms-lib
首先,我们从svelte-forms-lib 中导入createForm 函数。
import { createForm } from "svelte-forms-lib";
这个函数是将svelte-forms-lib 集成到表单中的核心部分。
CreateForm 让我们访问有用的表单帮助,如handleChange 和handleSubmit ,以及其他。我们将需要这些帮助函数来设置表单。
<script>
import { createForm } from "svelte-forms-lib";
const { form, handleChange, handleSubmit } = createForm({
initialValues: {
email: "",
password: "",
confirmPassword: "",
hobby: "",
checkbox: "",
},
onSubmit: (values) => {
alert(JSON.stringify(values));
},
});
</script>
<div class="container">
<h1>Registration Form</h1>
<form on:submit|preventDefault={handleSubmit}>
<div>
<input
type="text"
name="email"
bind:value={$form.email}
placeholder="Email"
on:change={handleChange}
/>
</div>
<div>
<input
type="password"
name="password"
bind:value={$form.password}
placeholder="Password"
on:change={handleChange}
/>
</div>
<div>
<input
type="password"
name="confirmPassword"
bind:value={$form.confirmPassword}
placeholder="Confirm password"
on:change={handleChange}
/>
</div>
<div>
<select name="hobby" bind:value={$form.hobby} on:blur={handleChange}>
<option value="">Select a hobby</option>
<option value="Eating">Eating</option>
<option value="Reading">Reading</option>
<option value="Sleeping">Sleeping</option>
</select>
</div>
<div>
<label for="checkbox">Check this box</label>
<input
name="checkbox"
type="checkbox"
bind:checked={$form.checkbox}
on:change={handleChange}
/>
</div>
<div>
<button type="submit">Register</button>
</div>
</form>
</div>
除了辅助函数之外,svelte-forms-lib 还公开了可观察的值,这些值为我们提供了关于表单当前状态的信息。在这篇文章中,我们将专注于使用form 和errors 的可观察值。然而,你可以在这里查看所有可用的观察变量的列表。
我们将一个配置对象作为参数传递给createForm 。在这里,我们定义了表单的initialValues 和处理表单提交的onSubmit 处理程序。
在配置了createForm 之后,我们需要将配置文件表单挂到svelte-forms-lib 上,这样它就可以跟踪表单的值并处理提交。
为了做到这一点,我们将handleSubmit 帮助器传递给form 元素。我们还将handleChange 传递给输入字段,并将bind 它们的值传递给form 观察器。
自定义验证svelte-forms-lib
现在我们知道了如何将svelte-forms-lib 集成到一个表单中,我们需要处理表单验证。
<script>
import { createForm } from "svelte-forms-lib";
const { form, errors, handleChange, handleSubmit } = createForm({
initialValues: {},
validate: (values) => {
let errors = {};
if (!values.email) {
errors.email = "Email is Required";
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(values.email)) {
errors.email = "Invalid emaill address";
}
if (!values.password) {
errors["password"] = "password is required";
}
if (!values.confirmPassword) {
errors["confirmPassword"] = "confirm password is required";
} else if (values.confirmPassword !== values.password) {
errors["confirmPassword"] = "password does not match";
}
if (!values.hobby) {
errors["hobby"] = "hobby is required";
}
if (!values.checkbox) {
errors.checkbox = "You must accept our terms";
}
return errors;
},
onSubmit: (values) => {
alert(JSON.stringify(values));
},
});
</script>
<div class="container">
<h1>Registration Form</h1>
<form on:submit|preventDefault={handleSubmit}>
<div>
<input
type="text"
name="email"
bind:value={$form.email}
placeholder="Email"
on:change={handleChange}
/>
{#if $errors.email}
<span class="error">{$errors.email}</span>
{/if}
</div>
<div>
<input
type="password"
name="password"
bind:value={$form.password}
placeholder="Password"
on:change={handleChange}
/>
{#if $errors.password}
<span class="error">{$errors.password}</span>
{/if}
</div>
<div>
<input
type="password"
name="confirmPassword"
bind:value={$form.confirmPassword}
placeholder="Confirm password"
on:change={handleChange}
/>
{#if $errors.confirmPassword}
<span class="error">{$errors.confirmPassword}</span>
{/if}
</div>
<div>
<select name="hobby" bind:value={$form.hobby} on:blur={handleChange}>
<option value="">Select a hobby</option>
<option value="Eating">Eating</option>
<option value="Reading">Reading</option>
<option value="Sleeping">Sleeping</option>
</select>
{#if $errors.hobby}
<span class="error">{$errors.hobby}</span>
{/if}
</div>
<div>
<label for="checkbox">Check this box</label>
<input
name="checkbox"
type="checkbox"
bind:checked={$form.checkbox}
on:change={handleChange}
/>
{#if $errors.checkbox}
<span class="error">{$errors.checkbox}</span>
{/if}
</div>
<div>
<button type="submit">Register</button>
</div>
</form>
</div>
除了用一个initialValues 对象和一个onSubmit 函数来配置createForm 外,我们还可以添加一个validate 回调来处理表单验证。
在这里,我们检查每个输入字段的状态,并根据这个状态,更新errors 对象。每当任何一个输入字段出现错误,我们就在if 块中显示出来。
邑的验证svelte-forms-lib
虽然我们可以为我们的表单创建一个自定义的验证,但我们也可以选择把这个责任交给Yup。
我们将与刚才创建的schema 验证对象一起工作。
<script>
import schema from "./schema";
import { createForm } from "svelte-forms-lib";
const { form, errors, handleChange, handleSubmit } = createForm({
initialValues: {
//initial values here
},
validationSchema: schema,
onSubmit: (values) => {
alert(JSON.stringify(values));
},
});
</script>
//profile form below
Svelte-forms-lib 通过一个validationSchema 道具提供对Yup验证的支持,该道具接收一个模式对象。我们传入我们定义的模式。你可以在这里找到本节的CodeSandbox链接。
自定义表单组件svelte-forms-lib
到目前为止,我们不得不向表单传递handleSubmit ,将每个字段绑定到各自的值,并向每个字段传递handleChange 。
虽然这能完成工作,但svelte-forms-lib 提供了一种更好的、不那么重复的方法来处理表单:自定义组件。
这些组件将减少模板,使表单代码非常简明。
<script>
import { Form, Field, ErrorMessage, Select } from "svelte-forms-lib";
import schema from "./schema";
const formProps = {
initialValues: {},
validationSchema: schema,
onSubmit: (values) => {
alert(JSON.stringify(values));
},
};
</script>
<div class="container">
<h1>Registration Form</h1>
<Form {...formProps}>
<div>
<Field type="email" name="email" placeholder="Email" />
<ErrorMessage name="email" />
</div>
<div>
<Field type="password" name="password" placeholder="Password" />
<ErrorMessage name="password" />
</div>
<div>
<Field type="password" name="confirmPassword" placeholder="Password" />
<ErrorMessage name="confirmPassword" />
</div>
<div>
<Select name="hobby">
<option value="">Select a hobby</option>
<option value="Eating">Eating</option>
<option value="Reading">Reading</option>
<option value="Sleeping">Sleeping</option>
</Select>
<ErrorMessage name="hobby" />
</div>
<div>
<label for="checkbox">Check this box</label>
<Field type="checkbox" name="checkbox" />
<ErrorMessage name="hobby" />
</div>
<div>
<button type="submit">Register</button>
</div>
</Form>
</div>
//profile form below
在这里,我们使用了<Form/>,<Field/>,<Select/>, 和<ErrorMessage/> 组件。
我们通过我们定义的formProps 变量将initialValues,onSubmit,validationSchema 传递给<Form/> 。name 和type 是需要的,以便<Field/> 正常工作并呈现适当的输入类型。
对于<ErrorMessage/> ,我们传入我们想要跟踪的输入字段的名称,如果该输入有错误,<ErrorMessage/> 将显示该错误。我们不再需要自己有条件地渲染错误了。
你可以在这里找到本节的CodeSandbox链接。
总结
在Svelte中创建表单既简单又非常复杂。在这篇文章中,我们已经了解了如何在Svelte中跟踪和存储输入值,如何用Yup处理验证,svelte-forms-lib ,以及我们可以通过不同的方式将这个强大的库集成到我们的表单中。
The postForm validation in Svelteappeared first onLogRocket Blog.