Skip to content

Form 表单

高性能订阅式表单,让表单开发变得简单。

何时使用

  • 用于创建一个实体或收集信息。
  • 需要对输入的数据类型进行校验时。

基本使用

基本的表单数据域控制展示,包含布局、初始化、验证、提交。

vue
<template>
  <g-form
    ref="formRef"
    :model="formState"
    name="basic"
    :label-col="{ span: 8 }"
    :wrapper-col="{ span: 16 }"
    autocomplete="off"
    @finish="onFinish"
    @finishFailed="onFinishFailed"
  >
    <g-form-item
      label="Username"
      name="username"
      :rules="[{ required: true, message: 'Please input your username!' }]"
    >
      <g-input v-model:value="formState.username" />
    </g-form-item>

    <g-form-item
      label="Password"
      name="password"
      :rules="[{ required: true, message: 'Please input your password!' }]"
    >
      <g-input-password v-model:value="formState.password" />
    </g-form-item>

    <g-form-item name="remember" :wrapper-col="{ offset: 8, span: 16 }">
      <g-checkbox v-model:checked="formState.remember">Remember me</g-checkbox>
    </g-form-item>

    <g-form-item :wrapper-col="{ offset: 8, span: 16 }">
      <g-button type="primary" html-type="submit">Submit</g-button>
    </g-form-item>
  </g-form>
</template>

<script>
import { reactive } from 'vue'

export default {
  setup() {
    const formState = reactive({
      username: '',
      password: '',
      remember: true,
    })
    
    const onFinish = (values) => {
      console.log('Success:', values)
    }
    
    const onFinishFailed = (errorInfo) => {
      console.log('Failed:', errorInfo)
    }
    
    return {
      formState,
      onFinish,
      onFinishFailed,
    }
  },
}
</script>

表单方法调用

通过 Form.useForm 对表单数据域进行交互。

vue
<template>
  <g-form
    :model="formState"
    name="basic"
    :label-col="{ span: 8 }"
    :wrapper-col="{ span: 16 }"
    autocomplete="off"
    @finish="onFinish"
    @finishFailed="onFinishFailed"
  >
    <g-form-item
      label="Username"
      name="username"
      :rules="[{ required: true, message: 'Please input your username!' }]"
    >
      <g-input v-model:value="formState.username" />
    </g-form-item>

    <g-form-item
      label="Password"
      name="password"
      :rules="[{ required: true, message: 'Please input your password!' }]"
    >
      <g-input-password v-model:value="formState.password" />
    </g-form-item>

    <g-form-item :wrapper-col="{ offset: 8, span: 16 }">
      <g-button type="primary" html-type="submit">Submit</g-button>
      <g-button style="margin-left: 10px;" @click="resetForm">Reset</g-button>
    </g-form-item>
  </g-form>
</template>

<script>
import { reactive } from 'vue'
import { Form } from '@/components'

export default {
  setup() {
    const { resetFields, validate, validateInfos } = Form.useForm(
      reactive({
        username: '',
        password: '',
      }),
      reactive({
        username: [{ required: true, message: 'Please input your username!' }],
        password: [{ required: true, message: 'Please input your password!' }],
      }),
    )
    
    const onFinish = (values) => {
      console.log('Success:', values)
    }
    
    const onFinishFailed = (errorInfo) => {
      console.log('Failed:', errorInfo)
    }
    
    const resetForm = () => {
      resetFields()
    }
    
    return {
      formState: validateInfos,
      onFinish,
      onFinishFailed,
      resetForm,
    }
  },
}
</script>

表单布局

表单有三种布局。

vue
<template>
  <div>
    <g-form
      :layout="formLayout"
      :model="formState"
      name="basic"
      :label-col="formLayout === 'horizontal' ? { span: 8 } : null"
      :wrapper-col="formLayout === 'horizontal' ? { span: 16 } : null"
    >
      <g-form-item label="Form Layout" name="layout">
        <g-radio-group v-model:value="formLayout">
          <g-radio-button value="horizontal">Horizontal</g-radio-button>
          <g-radio-button value="vertical">Vertical</g-radio-button>
          <g-radio-button value="inline">Inline</g-radio-button>
        </g-radio-group>
      </g-form-item>
      <g-form-item label="Field A">
        <g-input v-model:value="formState.fieldA" placeholder="input placeholder" />
      </g-form-item>
      <g-form-item label="Field B">
        <g-input v-model:value="formState.fieldB" placeholder="input placeholder" />
      </g-form-item>
      <g-form-item>
        <g-button type="primary">Submit</g-button>
      </g-form-item>
    </g-form>
  </div>
</template>

<script>
import { reactive, ref } from 'vue'

export default {
  setup() {
    const formLayout = ref('horizontal')
    const formState = reactive({
      fieldA: '',
      fieldB: '',
    })
    
    return {
      formLayout,
      formState,
    }
  },
}
</script>

表单验证

我们为表单控件定义了三种校验状态,你可以通过 validateStatus 属性为 g-form-item 设置校验状态。

vue
<template>
  <g-form
    :model="formState"
    name="validate_other"
    :label-col="{ span: 6 }"
    :wrapper-col="{ span: 14 }"
  >
    <g-form-item
      label="Fail"
      validate-status="error"
      help="Should be combination of numbers & alphabets"
    >
      <g-input v-model:value="formState.userName" placeholder="unavailable choice" />
    </g-form-item>

    <g-form-item label="Warning" validate-status="warning">
      <g-input v-model:value="formState.password" placeholder="Warning" />
    </g-form-item>

    <g-form-item
      label="Validating"
      validate-status="validating"
      help="The information is being validated..."
    >
      <g-input v-model:value="formState.confirmPassword" placeholder="I'm the content is being validated" />
    </g-form-item>

    <g-form-item label="Success" validate-status="success">
      <g-input v-model:value="formState.age" placeholder="I'm the content" />
    </g-form-item>

    <g-form-item label="Warning" validate-status="warning">
      <g-input v-model:value="formState.email" placeholder="Warning" />
    </g-form-item>

    <g-form-item
      label="Fail"
      validate-status="error"
      help="Should have something"
    >
      <g-date-picker style="width: 100%" />
    </g-form-item>
  </g-form>
</template>

<script>
import { reactive } from 'vue'

export default {
  setup() {
    const formState = reactive({
      userName: '',
      password: '',
      confirmPassword: '',
      age: '',
      email: '',
    })
    
    return {
      formState,
    }
  },
}
</script>

动态增减表单项

动态增加、减少表单项。

vue
<template>
  <g-form
    ref="formRef"
    name="dynamic_form_nest_item"
    :model="dynamicValidateForm"
    @finish="onFinish"
  >
    <g-space
      v-for="(user, index) in dynamicValidateForm.users"
      :key="user.key"
      style="display: flex; margin-bottom: 8px"
      align="baseline"
    >
      <g-form-item
        :name="['users', index, 'first']"
        :rules="{
          required: true,
          message: 'Missing first name',
        }"
      >
        <g-input v-model:value="user.first" placeholder="First Name" />
      </g-form-item>
      <g-form-item
        :name="['users', index, 'last']"
        :rules="{
          required: true,
          message: 'Missing last name',
        }"
      >
        <g-input v-model:value="user.last" placeholder="Last Name" />
      </g-form-item>
      <g-icon
        type="minus-circle-o"
        class="dynamic-delete-button"
        :disabled="dynamicValidateForm.users.length === 1"
        @click="removeUser(user)"
      />
    </g-space>
    <g-form-item>
      <g-button type="dashed" style="width: 60%" @click="addUser">
        <g-icon type="plus" /> Add field
      </g-button>
    </g-form-item>
    <g-form-item>
      <g-button type="primary" html-type="submit">Submit</g-button>
    </g-form-item>
  </g-form>
</template>

<script>
import { reactive } from 'vue'

export default {
  setup() {
    const dynamicValidateForm = reactive({
      users: [
        {
          first: '',
          last: '',
          key: Date.now(),
        },
      ],
    })
    
    const removeUser = (item) => {
      let index = dynamicValidateForm.users.indexOf(item)
      if (index !== -1) {
        dynamicValidateForm.users.splice(index, 1)
      }
    }
    
    const addUser = () => {
      dynamicValidateForm.users.push({
        first: '',
        last: '',
        key: Date.now(),
      })
    }
    
    const onFinish = (values) => {
      console.log('Received values of form:', values)
    }
    
    return {
      dynamicValidateForm,
      onFinish,
      removeUser,
      addUser,
    }
  },
}
</script>

<style>
.dynamic-delete-button {
  cursor: pointer;
  position: relative;
  top: 4px;
  font-size: 24px;
  color: #999;
  transition: all 0.3s;
}
.dynamic-delete-button:hover {
  color: #777;
}
.dynamic-delete-button[disabled] {
  cursor: not-allowed;
  opacity: 0.5;
}
</style>

复杂一点的控件

这里演示 g-form-item 内有多个元素的使用方式。

vue
<template>
  <g-form
    :model="formState"
    name="complex-form"
    :label-col="{ span: 6 }"
    :wrapper-col="{ span: 18 }"
  >
    <g-form-item label="Price">
      <g-input-group compact>
        <g-select
          v-model:value="formState.priceType"
          style="width: 30%"
        >
          <g-select-option value="RMB">RMB</g-select-option>
          <g-select-option value="Dollar">Dollar</g-select-option>
        </g-select>
        <g-input
          v-model:value="formState.price"
          style="width: 70%"
        />
      </g-input-group>
    </g-form-item>

    <g-form-item label="Website">
      <g-input-group compact>
        <g-select
          v-model:value="formState.protocol"
          style="width: 20%"
        >
          <g-select-option value="http://">http://</g-select-option>
          <g-select-option value="https://">https://</g-select-option>
        </g-select>
        <g-input
          v-model:value="formState.website"
          style="width: 80%"
          placeholder="mysite"
        />
      </g-input-group>
    </g-form-item>
  </g-form>
</template>

<script>
import { reactive } from 'vue'

export default {
  setup() {
    const formState = reactive({
      priceType: 'RMB',
      price: '',
      protocol: 'http://',
      website: '',
    })
    
    return {
      formState,
    }
  },
}
</script>

弹出层中的新建表单

当用户访问一个展示了某个列表的页面,想新建一项但又不想跳转页面时,可以用 Modal 弹出一个表单,用户填写必要信息后创建新的项。

vue
<template>
  <div>
    <g-button type="primary" @click="showModal">
      New Collection
    </g-button>
    <g-modal
      v-model:visible="visible"
      title="Create a new collection"
      ok-text="Create"
      cancel-text="Cancel"
      @ok="onCreate"
    >
      <g-form
        ref="formRef"
        :model="form"
        layout="vertical"
        name="form_in_modal"
      >
        <g-form-item
          name="name"
          label="Name"
          :rules="[{ required: true, message: 'Please input the name of collection!' }]"
        >
          <g-input v-model:value="form.name" />
        </g-form-item>
        <g-form-item name="description" label="Description">
          <g-input v-model:value="form.description" type="textarea" />
        </g-form-item>
        <g-form-item name="modifier" class="collection-create-form_last-form-item">
          <g-radio-group v-model:value="form.modifier">
            <g-radio value="public">Public</g-radio>
            <g-radio value="private">Private</g-radio>
          </g-radio-group>
        </g-form-item>
      </g-form>
    </g-modal>
  </div>
</template>

<script>
import { reactive, ref } from 'vue'

export default {
  setup() {
    const formRef = ref()
    const visible = ref(false)
    const form = reactive({
      name: '',
      description: '',
      modifier: 'public',
    })
    
    const showModal = () => {
      visible.value = true
    }
    
    const onCreate = () => {
      formRef.value
        .validate()
        .then(() => {
          console.log('values', form, toRaw(form))
          visible.value = false
          resetForm()
        })
        .catch((info) => {
          console.log('Validate Failed:', info)
        })
    }
    
    const resetForm = () => {
      formRef.value.resetFields()
    }
    
    return {
      formRef,
      visible,
      form,
      showModal,
      onCreate,
    }
  },
}
</script>

API

Form

参数说明类型默认值版本
colon配置 Form.Item 的 colon 的默认值booleantrue
hideRequiredMark隐藏所有表单项的必选标记booleanfalse
labelAlignlabel 标签的文本对齐方式left | rightright
labelCollabel 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12}sm: {span: 3, offset: 12}object-
labelWraplabel 标签的文本换行方式booleanfalse4.0.0
layout表单布局horizontal | vertical | inlinehorizontal
model表单数据对象object-
name表单名称,会作为表单字段 id 前缀使用string-
noStyletrue 时不带样式,作为纯字段控件使用booleanfalse
rules表单验证规则object-
scrollToFirstError提交失败自动滚动到第一个错误字段boolean | Optionsfalse
size设置字段组件的尺寸(仅限 antd 的表单控件)small | middle | large-
validateOnRuleChange是否在 rules 属性改变后立即触发一次验证booleantrue
validateTrigger统一设置字段校验规则string | string[]change1.5.0
wrapperCol需要为输入控件设置布局样式时,使用该属性,用法同 labelColobject-

Form 事件

事件名称说明回调参数
finish提交表单且数据验证成功后回调事件function(values)
finishFailed提交表单且数据验证失败后回调事件function({ values, errorFields, outOfDate })
submit数据验证成功后回调事件function(e)
validate任一表单项被校验后触发function(name, status, errorMsgs)

Form.Item

参数说明类型默认值版本
autoLink是否自动关联表单域,对于大部分情况都可以使用自动关联,如果不满足自动关联的条件,可以手动关联,参见下方注意事项booleantrue
colon配合 label 属性使用,表示是否显示 label 后面的冒号booleantrue
extra额外的提示信息,和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。string | slot-
hasFeedback配合 validateStatus 属性使用,展示校验状态图标,建议只配合 Input 组件使用booleanfalse
help提示信息,如不设置,则会根据校验规则自动生成string | slot-
htmlFor设置子元素 label htmlFor 属性string-
labellabel 标签的文本string | slot-
labelAlign标签文本对齐方式left | rightright
labelCollabel 标签布局,同 <Col> 组件,设置 span offset 值,如 {span: 3, offset: 12}sm: {span: 3, offset: 12}object-
name表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的string-
required是否必填,如不设置,则会根据校验规则自动生成booleanfalse
rules表单验证规则,设置字段的校验逻辑。点击此处查看示例object | array-
validateFirst当某一规则校验不通过时,是否停止剩下的规则的校验booleanfalse
validateStatus校验状态,如不设置,则会根据校验规则自动生成,可选:'success' 'warning' 'error' 'validating'string-
validateTrigger设置字段校验的时机string | string[]change
wrapperCol需要为输入控件设置布局样式时,使用该属性,用法同 labelColobject-

Form.useForm()

Form.useForm 通过 composition api 的方式来管理表单数据域。

js
import { Form } from 'ant-design-vue';

const useForm = Form.useForm;

useForm(modelRef, rulesRef, [options])

modelRef

表单数据,可以是 reactive 或者 ref 类型

rulesRef

表单校验规则,可以是 reactive 或者 ref 类型

options

参数说明类型默认值
immediate是否在创建时立即校验booleantrue
deep是否深度监听,对于对象类型字段,在其属性变化时也会触发校验booleantrue
validateOnRuleChange是否在 rules 属性改变后立即触发一次验证booleantrue
debounce防抖处理,与 lodash.debounce 完全一致object-

返回值

参数说明类型
resetFields重置表单(name?: NamePath) => void
clearValidate清理校验(name?: NamePath) => void
validate校验表单(name?: NamePath) => Promise
validateInfos校验信息ComputedRef<{ [key: string]: ValidateInfo }>

validateInfos

参数说明类型
autoLink是否自动关联,如果为 false,则需要手动设置 FormItem 的 validateStatus、help、hasFeedback 等属性。boolean
required是否必填boolean
validateStatus校验状态'success' | 'warning' | 'error' | 'validating'
help校验信息string

Released under the MIT License.