表單

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 元素繫結至 Form API。此外,透過像是 validateOn*initialValueresolvername 等 props,可以直接從此元件控制行為。


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

雖然 PrimeVue 元件對 Form 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>

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 props 修改此行為,以呈現不同的 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>

本節示範如何使用自訂的 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>

螢幕閱讀器

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

鍵盤支援

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