表单仍然是用户与网络交互方式的一个组成部分。在处理表单时,我们必须处理跟踪用户输入,验证和显示错误,以及处理表单的提交。
在这篇文章中,我们将学习输入绑定在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.