Diese Seite stellt die grundlegenden Konzepte und Terminologie vor, die in der @tanstack/vue-form Bibliothek verwendet werden. Wenn Sie sich mit diesen Konzepten vertraut machen, werden Sie die Bibliothek besser verstehen und damit arbeiten können.
Sie können Optionen für Ihr Formular erstellen, damit es von mehreren Formularen gemeinsam genutzt werden kann, indem Sie die Funktion formOptions verwenden.
Beispiel
const formOpts = formOptions({
defaultValues: {
firstName: '',
lastName: '',
hobbies: [],
} as Person,
})
const formOpts = formOptions({
defaultValues: {
firstName: '',
lastName: '',
hobbies: [],
} as Person,
})
Eine Formularinstanz ist ein Objekt, das ein einzelnes Formular repräsentiert und Methoden und Eigenschaften für die Arbeit mit dem Formular bereitstellt. Sie erstellen eine Formularinstanz mit der Funktion useForm. Die Funktion akzeptiert ein Objekt mit einer onSubmit-Funktion, die beim Absenden des Formulars aufgerufen wird.
const form = useForm({
...formOpts,
onSubmit: async ({ value }) => {
// Do something with form data
console.log(value)
},
})
const form = useForm({
...formOpts,
onSubmit: async ({ value }) => {
// Do something with form data
console.log(value)
},
})
Sie können auch eine Formularinstanz erstellen, ohne formOptions zu verwenden, indem Sie die eigenständige useForm API verwenden.
const form = useForm({
onSubmit: async ({ value }) => {
// Do something with form data
console.log(value)
},
defaultValues: {
firstName: '',
lastName: '',
hobbies: [],
} as Person,
})
const form = useForm({
onSubmit: async ({ value }) => {
// Do something with form data
console.log(value)
},
defaultValues: {
firstName: '',
lastName: '',
hobbies: [],
} as Person,
})
Ein Feld repräsentiert ein einzelnes Formulareingabeelement, wie z. B. ein Texteingabefeld oder eine Checkbox. Felder werden mit der Komponente form.Field erstellt, die von der Formularinstanz bereitgestellt wird. Die Komponente akzeptiert eine name-Prop, die mit einem Schlüssel in den Standardwerten des Formulars übereinstimmen muss. Sie akzeptiert auch einen benannten Slot, der durch die v-slot-Direktive definiert ist und ein field-Objekt als Argument erhält.
Beispiel
<template>
<!-- ... -->
<form.Field name="fullName">
<template v-slot="{ field }">
<input
:name="field.name"
:value="field.state.value"
@blur="field.handleBlur"
@input="(e) => field.handleChange(e.target.value)"
/>
</template>
</form.Field>
<!-- ... -->
</template>
<template>
<!-- ... -->
<form.Field name="fullName">
<template v-slot="{ field }">
<input
:name="field.name"
:value="field.state.value"
@blur="field.handleBlur"
@input="(e) => field.handleChange(e.target.value)"
/>
</template>
</form.Field>
<!-- ... -->
</template>
Jedes Feld hat seinen eigenen Zustand, der seinen aktuellen Wert, seinen Validierungsstatus, Fehlermeldungen und andere Metadaten umfasst. Sie können auf den Zustand eines Feldes über die Eigenschaft field().state zugreifen.
Beispiel
const {
value,
meta: { errors, isValidating },
} = field.state
const {
value,
meta: { errors, isValidating },
} = field.state
Es gibt vier Zustände in den Metadaten, die nützlich sein können, um zu sehen, wie der Benutzer mit einem Feld interagiert.
const { isTouched, isDirty, isPristine, isBlurred } = field.state.meta
const { isTouched, isDirty, isPristine, isBlurred } = field.state.meta

Nicht-persistenter dirty Zustand
Persistenter dirty Zustand
Wir haben uns für das persistente 'dirty'-Zustandsmodell entschieden. Um auch einen nicht-persistenten 'dirty'-Zustand zu unterstützen, führen wir ein zusätzliches Flag ein.
const { isDefaultValue, isTouched } = field.state.meta
// The following line will re-create the non-Persistent `dirty` functionality.
const nonPersistentIsDirty = !isDefaultValue
const { isDefaultValue, isTouched } = field.state.meta
// The following line will re-create the non-Persistent `dirty` functionality.
const nonPersistentIsDirty = !isDefaultValue

Die Feld-API ist ein Objekt, das von einem benannten Slot über die v-slot-Direktive bereitgestellt wird. Dieser Slot empfängt ein Argument namens field, das Methoden und Eigenschaften für die Arbeit mit dem Zustand des Feldes bereitstellt.
Beispiel
<template v-slot="{ field }">
<input
:name="field.name"
:value="field.state.value"
@blur="field.handleBlur"
@input="(e) => field.handleChange(e.target.value)"
/>
</template>
<template v-slot="{ field }">
<input
:name="field.name"
:value="field.state.value"
@blur="field.handleBlur"
@input="(e) => field.handleChange(e.target.value)"
/>
</template>
@tanstack/vue-form bietet sofort sowohl synchrone als auch asynchrone Validierung. Validierungsfunktionen können über die form.Field-Komponente mit der validators-Prop übergeben werden.
Beispiel
<template>
<!-- ... -->
<form.Field
name="firstName"
:validators="{
onChange: ({ value }) =>
!value
? `A first name is required`
: value.length < 3
? `First name must be at least 3 characters`
: undefined,
onChangeAsync: async ({ value }) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
return value.includes('error') && 'No "error" allowed in first name'
},
}"
>
<template v-slot="{ field }">
<input
:value="field.state.value"
@input="(e) => field.handleChange(e.target.value)"
@blur="field.handleBlur"
/>
<FieldInfo :field="field" />
</template>
</form.Field>
<!-- ... -->
</template>
<template>
<!-- ... -->
<form.Field
name="firstName"
:validators="{
onChange: ({ value }) =>
!value
? `A first name is required`
: value.length < 3
? `First name must be at least 3 characters`
: undefined,
onChangeAsync: async ({ value }) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
return value.includes('error') && 'No "error" allowed in first name'
},
}"
>
<template v-slot="{ field }">
<input
:value="field.state.value"
@input="(e) => field.handleChange(e.target.value)"
@blur="field.handleBlur"
/>
<FieldInfo :field="field" />
</template>
</form.Field>
<!-- ... -->
</template>
Zusätzlich zu handgeschriebenen Validierungsoptionen unterstützen wir auch die Standard Schema Spezifikation.
Sie können ein Schema mit einer beliebigen der Bibliotheken definieren, die die Spezifikation implementieren, und es an einen Formular- oder Feldvalidator übergeben.
Unterstützte Bibliotheken umfassen:
<script setup lang="ts">
import { useForm } from '@tanstack/vue-form'
import { z } from 'zod'
const form = useForm({
// ...
})
const onChangeFirstName = z.string().refine(
async (value) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
return !value.includes('error')
},
{
message: "No 'error' allowed in first name",
},
)
</script>
<template>
<!-- ... -->
<form.Field
name="firstName"
:validators="{
onChange: z.string().min(3, 'First name must be at least 3 characters'),
onChangeAsyncDebounceMs: 500,
onChangeAsync: onChangeFirstName,
}"
>
<template v-slot="{ field, state }">
<label :htmlFor="field.name">First Name:</label>
<input
:id="field.name"
:name="field.name"
:value="field.state.value"
@input="(e) => field.handleChange((e.target as HTMLInputElement).value)"
@blur="field.handleBlur"
/>
<FieldInfo :state="state" />
</template>
</form.Field>
<!-- ... -->
</template>
<script setup lang="ts">
import { useForm } from '@tanstack/vue-form'
import { z } from 'zod'
const form = useForm({
// ...
})
const onChangeFirstName = z.string().refine(
async (value) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
return !value.includes('error')
},
{
message: "No 'error' allowed in first name",
},
)
</script>
<template>
<!-- ... -->
<form.Field
name="firstName"
:validators="{
onChange: z.string().min(3, 'First name must be at least 3 characters'),
onChangeAsyncDebounceMs: 500,
onChangeAsync: onChangeFirstName,
}"
>
<template v-slot="{ field, state }">
<label :htmlFor="field.name">First Name:</label>
<input
:id="field.name"
:name="field.name"
:value="field.state.value"
@input="(e) => field.handleChange((e.target as HTMLInputElement).value)"
@blur="field.handleBlur"
/>
<FieldInfo :state="state" />
</template>
</form.Field>
<!-- ... -->
</template>
@tanstack/vue-form bietet verschiedene Möglichkeiten, Formular- und Feldzustandsänderungen zu abonnieren, insbesondere die Methode form.useStore und die Komponente form.Subscribe. Diese Methoden ermöglichen es Ihnen, die Rendering-Leistung Ihres Formulars zu optimieren, indem Sie Komponenten nur dann aktualisieren, wenn dies erforderlich ist.
Beispiel
<script setup lang="ts">
// ...
const firstName = form.useStore((state) => state.values.firstName)
</script>
<template>
<!-- ... -->
<form.Subscribe>
<template v-slot="{ canSubmit, isSubmitting }">
<button type="submit" :disabled="!canSubmit">
{{ isSubmitting ? '...' : 'Submit' }}
</button>
</template>
</form.Subscribe>
<!-- ... -->
</template>
<script setup lang="ts">
// ...
const firstName = form.useStore((state) => state.values.firstName)
</script>
<template>
<!-- ... -->
<form.Subscribe>
<template v-slot="{ canSubmit, isSubmitting }">
<button type="submit" :disabled="!canSubmit">
{{ isSubmitting ? '...' : 'Submit' }}
</button>
</template>
</form.Subscribe>
<!-- ... -->
</template>
@tanstack/vue-form ermöglicht es Ihnen, auf bestimmte Auslöser zu reagieren und diese zu "lauschen", um Seiteneffekte auszulösen.
Beispiel
<template>
<form.Field
name="country"
:listeners="{
onChange: ({ value }) => {
console.log(`Country changed to: ${value}, resetting province`)
form.setFieldValue('province', '')
},
}"
>
<template v-slot="{ field }">
<input
:value="field.state.value"
@input="(e) => field.handleChange(e.target.value)"
/>
</template>
</form.Field>
</template>
<template>
<form.Field
name="country"
:listeners="{
onChange: ({ value }) => {
console.log(`Country changed to: ${value}, resetting province`)
form.setFieldValue('province', '')
},
}"
>
<template v-slot="{ field }">
<input
:value="field.state.value"
@input="(e) => field.handleChange(e.target.value)"
/>
</template>
</form.Field>
</template>
Weitere Informationen finden Sie unter Listener
Hinweis: Die Verwendung der Methode form.useField zur Erzielung von Reaktivität wird nicht empfohlen, da sie dafür konzipiert ist, sorgfältig innerhalb der form.Field-Komponente verwendet zu werden. Möglicherweise möchten Sie stattdessen form.useStore verwenden.
Array-Felder ermöglichen es Ihnen, eine Liste von Werten innerhalb eines Formulars zu verwalten, wie z. B. eine Liste von Hobbys. Sie können ein Array-Feld mit der form.Field Komponente mit der Prop mode="array" erstellen.
Wenn Sie mit Array-Feldern arbeiten, können Sie die Methoden pushValue, removeValue, swapValues und moveValue des Feldes verwenden, um Werte im Array hinzuzufügen, zu entfernen und zu tauschen.
Beispiel
<template>
<form @submit.prevent.stop="form.handleSubmit">
<form.Field name="hobbies" mode="array">
<template v-slot="{ field: hobbiesField }">
<div>
Hobbies
<div>
<div
v-if="
Array.isArray(hobbiesField.state.value) &&
!hobbiesField.state.value.length
"
>
No hobbies found.
</div>
<div v-else>
<div v-for="(_, i) in hobbiesField.state.value" :key="i">
<form.Field :name="`hobbies[${i}].name`">
<template v-slot="{ field }">
<div>
<label :for="field.name">Name:</label>
<input
:id="field.name"
:name="field.name"
:value="field.state.value"
@blur="field.handleBlur"
@input="(e) => field.handleChange(e.target.value)"
/>
<button
type="button"
@click="hobbiesField.removeValue(i)"
>
X
</button>
<FieldInfo :field="field" />
</div>
</template>
</form.Field>
<form.Field :name="`hobbies[${i}].description`">
<template v-slot="{ field }">
<div>
<label :for="field.name">Description:</label>
<input
:id="field.name"
:name="field.name"
:value="field.state.value"
@blur="field.handleBlur"
@input="(e) => field.handleChange(e.target.value)"
/>
<FieldInfo :field="field" />
</div>
</template>
</form.Field>
</div>
</div>
<button
type="button"
@click="
hobbiesField.pushValue({
name: '',
description: '',
yearsOfExperience: 0,
})
"
>
Add hobby
</button>
</div>
</div>
</template>
</form.Field>
</form>
</template>
<template>
<form @submit.prevent.stop="form.handleSubmit">
<form.Field name="hobbies" mode="array">
<template v-slot="{ field: hobbiesField }">
<div>
Hobbies
<div>
<div
v-if="
Array.isArray(hobbiesField.state.value) &&
!hobbiesField.state.value.length
"
>
No hobbies found.
</div>
<div v-else>
<div v-for="(_, i) in hobbiesField.state.value" :key="i">
<form.Field :name="`hobbies[${i}].name`">
<template v-slot="{ field }">
<div>
<label :for="field.name">Name:</label>
<input
:id="field.name"
:name="field.name"
:value="field.state.value"
@blur="field.handleBlur"
@input="(e) => field.handleChange(e.target.value)"
/>
<button
type="button"
@click="hobbiesField.removeValue(i)"
>
X
</button>
<FieldInfo :field="field" />
</div>
</template>
</form.Field>
<form.Field :name="`hobbies[${i}].description`">
<template v-slot="{ field }">
<div>
<label :for="field.name">Description:</label>
<input
:id="field.name"
:name="field.name"
:value="field.state.value"
@blur="field.handleBlur"
@input="(e) => field.handleChange(e.target.value)"
/>
<FieldInfo :field="field" />
</div>
</template>
</form.Field>
</div>
</div>
<button
type="button"
@click="
hobbiesField.pushValue({
name: '',
description: '',
yearsOfExperience: 0,
})
"
>
Add hobby
</button>
</div>
</div>
</template>
</form.Field>
</form>
</template>
Dies sind die grundlegenden Konzepte und Terminologie, die in der @tanstack/vue-form Bibliothek verwendet werden. Das Verständnis dieser Konzepte wird Ihnen helfen, effektiver mit der Bibliothek zu arbeiten und komplexe Formulare mühelos zu erstellen.
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.