表單

PrimeVue 表單函式庫提供全面的表單狀態管理,並內建驗證支援。

表單附加元件可從 npm 註冊表下載。


# Using npm
npm install @primevue/forms

# Using yarn
yarn add @primevue/forms

# Using pnpm
pnpm add @primevue/forms

表單元件負責管理表單狀態,且必須封裝表單欄位。


import { Form } from '@primevue/forms';

所有 PrimeVue 表單元件都設計為與表單函式庫無縫整合。不使用標準的 v-model,而是使用 name 屬性連結追蹤值、錯誤和動作的狀態物件。表單元件提供四個主要的屬性進行狀態管理。

屬性描述
v-slot="$form"公開追蹤欄位狀態管理的主要 $form 物件。
initialValues指定啟動表單的預設值。
resolver驗證處理常式,用於實作驗證或繫結像是 ZodYupValibot 等的結構描述。
@submit在提交表單時執行的事件處理常式。

<Form v-slot="$form" :initialValues :resolver @submit="onFormSubmit" class="flex flex-col gap-4 w-full sm:w-56">
    <div class="flex flex-col gap-1">
        <InputText name="username" type="text" placeholder="Username" fluid />
        <Message v-if="$form.username?.invalid" severity="error" size="small" variant="simple">{{ $form.username.error?.message }}</Message>
    </div>
    <Button type="submit" severity="secondary" label="Submit" />
</Form>

$form 物件追蹤欄位的狀態管理。每個欄位都與 name 屬性連結。請檢視 API 文件中的 FormFieldState 類型,以瞭解每個屬性的詳細資訊。

表單狀態
{
  "valid": true
}

<Form v-slot="$form" :initialValues :resolver @submit="onFormSubmit" class="grid lg:grid-cols-2 gap-4 w-full">
    <div class="flex flex-col justify-center items-center gap-4">
        <InputText name="username" type="text" placeholder="Username" class="w-full sm:w-56" />
        <Button type="submit" severity="secondary" label="Submit" class="w-full sm:w-56" />
    </div>
    <Fieldset legend="Form States" class="h-80 overflow-auto">
        <pre class="whitespace-pre-wrap">{{ $form }}</pre>
    </Fieldset>
</Form>

驗證是透過 resolver 屬性實作。自訂解析器負責處理驗證,並傳回包含鍵值對的 errors 物件,其中鍵是表單欄位名稱,值是錯誤物件資料的陣列。為了提高生產力,我們建議使用結構描述驗證函式庫,而非建置自己的自訂驗證邏輯。表單函式庫為常用的選項提供內建解析器,包括 ZodYupJoiValibotSuperstruct,可以從 @primevue/forms/resolvers 路徑匯入。

結構描述

<Form v-slot="$form" :initialValues :resolver="resolver" @submit="onFormSubmit" class="flex flex-col gap-4 w-full sm:w-56">
    <div class="flex flex-col gap-1">
        <InputText name="username" type="text" placeholder="Username" fluid />
        <Message v-if="$form.username?.invalid" severity="error" size="small" variant="simple">{{ $form.username.error.message }}</Message>
    </div>
    <Button type="submit" severity="secondary" label="Submit" />
</Form>

表單元件支援彈性的驗證觸發,允許在值更新、失去焦點事件、表單掛載或提交時驗證。這些行為可以在表單層級或透過 formControl 屬性的 validateOnValueUpdatevalidateOnBlurvalidateOnMountvalidateOnSubmit 選項在特定欄位上設定。

在此範例中,表單停用表單層級的 validateOnValueUpdate 並啟用 validateOnBlur,並在掛載時驗證 firstNamefirstName 欄位會在本地覆寫表單層級設定。


<Form v-slot="$form" :initialValues :resolver :validateOnValueUpdate="false" :validateOnBlur="true" :validateOnMount="['firstName']" @submit="onFormSubmit" class="flex flex-col gap-4 w-full sm:w-56">
    <div class="flex flex-col gap-1">
        <InputText name="username" type="text" placeholder="Username" fluid />
        <Message v-if="$form.username?.invalid" severity="error" size="small" variant="simple">{{ $form.username.error.message }}</Message>
    </div>
    <div class="flex flex-col gap-1">
        <InputText name="firstName" type="text" placeholder="First Name" fluid :formControl="{ validateOnValueUpdate: true }" />
        <Message v-if="$form.firstName?.invalid" severity="error" size="small" variant="simple">{{ $form.firstName.error.message }}</Message>
    </div>
    <div class="flex flex-col gap-1">
        <InputText name="lastName" type="text" placeholder="Last Name" fluid />
        <Message v-if="$form.lastName?.invalid" severity="error" size="small" variant="simple">{{ $form.lastName.error.message }}</Message>
    </div>
    <Button type="submit" severity="secondary" label="Submit" />
</Form>

FormField 是一個輔助元件,為輸入元素提供驗證和追蹤,提供更彈性的結構,將 PrimeVue、非 PrimeVue 元件或原生 HTML 元素繫結至表單 API。此外,透過像是 validateOn*initialValueresolvername 等屬性,可以直接從此元件控制行為。


import { FormField } from '@primevue/forms';

儘管 PrimeVue 元件內建支援表單 API,您可能仍偏好使用以 FormField 包裝的元件。這純粹是偏好問題,例如在您也將 FormField 用於其他第三方元件、您自己的自訂元件和原生元素的情況下,為了保持一致性,這可能是一個選項。


<Form :resolver @submit="onFormSubmit" class="flex flex-col gap-4 w-full sm:w-56">
    <FormField v-slot="$field" name="username" initialValue="" class="flex flex-col gap-1">
        <InputText type="text" placeholder="Username" />
        <Message v-if="$field?.invalid" severity="error" size="small" variant="simple">{{ $field.error?.message }}</Message>
    </FormField>
    <Button type="submit" severity="secondary" label="Submit" />
</Form>

表單 API 並不嚴格繫結至 PrimeVue 元件,而是為任何原生 HTML 元素、您自己的自訂元件或第三方函式庫提供彈性的方式來管理驗證和狀態。


<Form :resolver @submit="onFormSubmit" class="flex flex-col gap-4 w-full sm:w-56">
    <FormField v-slot="$field" name="username" initialValue="" class="flex flex-col gap-1">
        <input type="text" placeholder="Username" :class="[{ error: $field?.invalid }]" v-bind="$field.props" />
        <Message v-if="$field?.invalid" severity="error" size="small" variant="simple">{{ $field.error?.message }}</Message>
    </FormField>
    <FormField v-slot="$field" name="password" initialValue="PrimeVue" class="flex flex-col gap-1">
        <input v-model="$field.value" type="password" placeholder="Password" :class="[{ error: $field?.invalid }]" @input="$field.onInput" @blur="$field.onBlur" @change="$field.onChange" />
        <Message v-if="$field?.invalid" severity="error" size="small" variant="simple">{{ $field.error?.message }}</Message>
    </FormField>
    <Button type="submit" severity="secondary" label="Submit" />
</Form>

每個 FormField 都可以有自己的專屬解析器,讓您可以為個別欄位定義自訂驗證邏輯。這種彈性可啟用量身打造的驗證規則,確保每個表單欄位都符合特定條件。


<Form :initialValues :resolver @submit="onFormSubmit" class="flex flex-col gap-4 w-full sm:w-80">
    <FormField v-slot="$field" name="username" initialValue="" :resolver="zodUserNameResolver" class="flex flex-col gap-1">
        <InputText type="text" placeholder="Username" />
        <Message v-if="$field?.invalid" severity="error" size="small" variant="simple">{{ $field.error?.message }}</Message>
    </FormField>
    <FormField v-slot="$field" name="firstname" initialValue="" :resolver="yupFirstNameResolver" class="flex flex-col gap-1">
        <InputText type="text" placeholder="First Name" />
        <Message v-if="$field?.invalid" severity="error" size="small" variant="simple">{{ $field.error?.message }}</Message>
    </FormField>
    <FormField v-slot="$field" name="lastname" initialValue="" :resolver="valibotLastNameResolver" class="flex flex-col gap-1">
        <InputText type="text" placeholder="Last Name" />
        <Message v-if="$field?.invalid" severity="error" size="small" variant="simple">{{ $field.error?.message }}</Message>
    </FormField>
    <FormField v-slot="$field" name="password" initialValue="" :resolver="customPasswordResolver" class="flex flex-col gap-1">
        <Password type="text" placeholder="Password" :feedback="false" toggleMask fluid />
        <Message v-if="$field?.invalid" severity="error" size="small" variant="simple">{{ $field.error?.message }}</Message>
    </FormField>
    <FormField v-slot="$field" name="details" class="flex flex-col gap-1">
        <Textarea placeholder="Details" />
        <Message v-if="$field?.invalid" severity="error" size="small" variant="simple">{{ $field.error?.message }}</Message>
    </FormField>
    <Button type="submit" severity="secondary" label="Submit" />
</Form>

它會呈現為 HTML div 元素,但可以使用 asasChild 屬性來修改此行為,以呈現不同的 HTML 元素或傳遞自訂元件,進而提高表單結構的彈性。


<Form :resolver @submit="onFormSubmit" class="flex flex-col gap-4 w-full sm:w-56">
    <FormField v-slot="$field" as="section" name="username" initialValue="" class="flex flex-col gap-2">
        <InputText type="text" placeholder="Username" />
        <Message v-if="$field?.invalid" severity="error" size="small" variant="simple">{{ $field.error?.message }}</Message>
    </FormField>
    <FormField v-slot="$field" asChild name="password" initialValue="">
        <section class="flex flex-col gap-2">
            <Password type="text" placeholder="Password" :feedback="false" toggleMask fluid />
            <Message v-if="$field?.invalid" severity="error" size="small" variant="simple">{{ $field.error?.message }}</Message>
        </section>
    </FormField>
    <Button type="submit" severity="secondary" label="Submit" />
</Form>

submit 回呼會傳回一個物件,其中封裝表單的有效性、任何現有錯誤及其目前狀態。這能夠在提交時存取表單值、驗證狀態和任何現有錯誤。請檢視 API 文件中的 FormSubmitEvent,以瞭解更多有關可用事件資料的資訊。


<Form v-slot="$form" :initialValues :resolver @submit="onFormSubmit" class="flex flex-col gap-4 w-full sm:w-60">
    <div class="flex flex-col gap-1">
        <InputText name="username" type="text" placeholder="Username" fluid />
        <Message v-if="$form.username?.invalid" severity="error" size="small" variant="simple">{{ $form.username.error.message }}</Message>
    </div>
    <div class="flex flex-col gap-1">
        <Password name="password" placeholder="Password" :feedback="false" toggleMask fluid />
        <Message v-if="$form.password?.invalid" severity="error" size="small" variant="simple">
            <ul class="my-0 px-4 flex flex-col gap-1">
                <li v-for="(error, index) of $form.password.errors" :key="index">{{ error.message }}</li>
            </ul>
        </Message>
    </div>
    <Button type="submit" severity="secondary" label="Submit" />
</Form>

此章節示範如何使用自訂的表單元件建立動態表單。它展示根據提供的設定動態產生表單欄位的範例,允許彈性的表單結構。此範例中顯示的 Dynamic* 元件並非內建,僅供範例用途。第一個表單使用宣告式方法,而第二個表單則採用程式化方法。我們建議在 StackBlitz 中執行此範例,以檢視完整的實作。

表單 1
表單 2

<Fieldset legend="Form 1" pt:content:class="flex justify-center">
    <DynamicForm @submit="onFormSubmit('Form 1', $event)">
        <DynamicFormField groupId="userId_1" name="username">
            <DynamicFormLabel>Username</DynamicFormLabel>
            <DynamicFormControl defaultValue="PrimeVue" fluid :schema="userNameSchema" />
            <DynamicFormMessage />
        </DynamicFormField>
        <DynamicFormField groupId="passId_1" name="password">
            <DynamicFormLabel>Password</DynamicFormLabel>
            <DynamicFormControl as="Password" :feedback="false" toggleMask fluid :schema="passwordSchema" />
            <DynamicFormMessage errorType="minimum" />
            <DynamicFormMessage errorType="maximum" />
            <DynamicFormMessage errorType="uppercase" severity="warn" />
            <DynamicFormMessage errorType="lowercase" severity="warn" />
            <DynamicFormMessage errorType="number" severity="secondary" />
        </DynamicFormField>
        <DynamicFormSubmit />
    </DynamicForm>
</Fieldset>

<Fieldset legend="Form 2" pt:content:class="flex justify-center">
    <DynamicForm :fields @submit="onFormSubmit('Form 2', $event)" />
</Fieldset>

螢幕閱讀器

表單不需要任何角色和屬性。

鍵盤支援

元件不包含任何互動元素。