VEUI

VEUI on GitHub
Play!中文

Form

Examples

Action buttons

Use the actions slot to provide form action buttons.

请选择
请选择日期
Edit this demo on GitHubEdit
<template>
<article>
  <veui-form
    :data="formData"
    @submit="handleSubmit"
  >
    <veui-field label="型号">
      <veui-select
        v-model="formData.model"
        :options="models"
      />
    </veui-field>
    <veui-field label="日期">
      <veui-date-picker
        v-model="formData.date"
      />
    </veui-field>
    <template #actions>
      <veui-button
        ui="primary"
        type="submit"
      >
        提交
      </veui-button>
      <veui-button>取消</veui-button>
    </template>
  </veui-form>
</article>
</template>

<script>
import { Form, Field, Button, Select, DatePicker } from 'veui'

export default {
  components: {
    'veui-form': Form,
    'veui-field': Field,
    'veui-button': Button,
    'veui-select': Select,
    'veui-date-picker': DatePicker
  },
  data () {
    return {
      models: [
        {
          label: 'APTX-4867',
          value: 'aptx-4867'
        },
        {
          label: 'APTX-4868',
          value: 'aptx-4868'
        },
        {
          label: 'APTX-4869',
          value: 'aptx-4869'
        },
        {
          label: 'APTX-4870',
          value: 'aptx-4870'
        }
      ],
      formData: {
        model: null,
        date: null
      }
    }
  },
  methods: {
    handleSubmit (data) {
      this.$toast(JSON.stringify(data, null, 2))
    }
  }
}
</script>

Read-only

Set readonly to make the internal form items read-only.

Edit this demo on GitHubEdit
<template>
<article>
  <section>
    <veui-checkbox v-model="readonly">
      只读
    </veui-checkbox>
  </section>
  <veui-form
    :data="formData"
    :readonly="readonly"
  >
    <veui-field label="姓名">
      <veui-input v-model="formData.name"/>
    </veui-field>
  </veui-form>
</article>
</template>

<script>
import { Form, Field, Input, Checkbox } from 'veui'

export default {
  components: {
    'veui-checkbox': Checkbox,
    'veui-form': Form,
    'veui-field': Field,
    'veui-input': Input
  },
  data () {
    return {
      readonly: true,
      formData: {
        name: ''
      }
    }
  }
}
</script>

<style lang="less" scoped>
section {
  margin-bottom: 20px;
}
</style>

Disabled

Set disabled to disable the internal form items.

Edit this demo on GitHubEdit
<template>
<article>
  <section>
    <veui-checkbox v-model="disabled">
      禁用
    </veui-checkbox>
  </section>
  <veui-form
    :data="formData"
    :disabled="disabled"
  >
    <veui-field label="姓名">
      <veui-input v-model="formData.name"/>
    </veui-field>
  </veui-form>
</article>
</template>

<script>
import { Form, Field, Input, Checkbox } from 'veui'

export default {
  components: {
    'veui-checkbox': Checkbox,
    'veui-form': Form,
    'veui-field': Field,
    'veui-input': Input
  },
  data () {
    return {
      disabled: true,
      formData: {
        name: ''
      }
    }
  }
}
</script>

<style lang="less" scoped>
section {
  margin-bottom: 20px;
}
</style>

Help text

辅助信息位置:
至少 2 个字符
精确到门牌号
Edit this demo on GitHubEdit
<template>
<article>
  <section>
    <span class="label-text">辅助信息位置:</span>
    <veui-radio-button-group
      v-model="helpPosition"
      ui="s"
      :items="helpPositions"
    />
    <veui-checkbox
      v-model="labelPosition"
      true-value="top"
      false-value="side"
      ui="s"
      style="margin-left: 8px"
    >
      上下布局
    </veui-checkbox>
  </section>
  <veui-form
    :data="formData"
    :label-position="labelPosition"
  >
    <veui-field
      name="name"
      label="姓名"
      tip="你的全名"
      help="至少 2 个字符"
      :help-position="helpPosition"
    >
      <veui-input v-model="formData.name"/>
    </veui-field>
    <veui-field
      name="address"
      label="地址"
      tip="居住地的详细地址"
      help="精确到门牌号"
      :help-position="helpPosition"
    >
      <veui-input v-model="formData.address"/>
    </veui-field>
  </veui-form>
</article>
</template>

<script>
import { Form, Field, Input, Checkbox, RadioButtonGroup } from 'veui'

export default {
  components: {
    'veui-form': Form,
    'veui-field': Field,
    'veui-input': Input,
    'veui-radio-button-group': RadioButtonGroup,
    'veui-checkbox': Checkbox
  },
  data () {
    return {
      formData: {
        name: '',
        address: ''
      },
      helpPositions: [
        { label: 'top', value: 'top' },
        { label: 'side', value: 'side' },
        { label: 'bottom', value: 'bottom' }
      ],
      helpPosition: 'side',
      labelPosition: 'side'
    }
  }
}
</script>

<style lang="less" scoped>
section {
  margin-bottom: 20px;
}

.label-text {
   font-size: 12px;
   margin-right: 8px;
 }
</style>

Rules

Edit this demo on GitHubEdit
<template>
<article class="veui-form-demo">
  <veui-form
    ref="form"
    :data="data"
  >
    <veui-field
      field="phone"
      name="phone"
      :rules="phoneRule"
      label="手机"
    >
      <veui-input
        v-model="data.phone"
        name="phone"
        autocomplete="off"
      />
    </veui-field>

    <template #actions>
      <veui-button
        ui="primary"
        type="submit"
      >提交</veui-button>
    </template>
  </veui-form>
</article>
</template>

<script>
import {
  Form,
  Field,
  Input,
  Button
} from 'veui'

export default {
  name: 'demo-form',
  components: {
    'veui-input': Input,
    'veui-button': Button,
    'veui-form': Form,
    'veui-field': Field
  },
  data () {
    return {
      data: {
        phone: '1888888888a'
      },
      phoneRule: [
        {
          name: 'pattern',
          value: /^1\d{10}$/,
          message: '{value} 不是正确的手机号',
          triggers: 'blur'
        }
      ]
    }
  }
}
</script>

Inline rules

Edit this demo on GitHubEdit
<template>
<article class="veui-form-demo">
  <veui-form
    ref="form"
    :data="data"
  >
    <veui-field
      label="密码"
      name="password"
      :rules="[
        { name: 'required', triggers: 'input,blur' },
        { name: 'minLength', value: '6', triggers: 'blur' }
      ]"
    >
      <veui-input
        v-model="data.password"
        type="password"
      />
    </veui-field>

    <veui-field
      label="确认密码"
      name="password2"
      :rules="p2Rules"
    >
      <veui-input
        v-model="data.password2"
        type="password"
      />
    </veui-field>
  </veui-form>
</article>
</template>

<script>
import {
  Form,
  Field,
  Input
} from 'veui'

export default {
  name: 'demo-form',
  components: {
    'veui-input': Input,
    'veui-form': Form,
    'veui-field': Field
  },
  data () {
    return {
      data: {
        password: '',
        password2: ''
      }
    }
  },
  computed: {
    p2Rules () {
      return [
        { name: 'required', triggers: 'input,blur' },
        {
          name: 'prefix',
          value: this.data.password,
          triggers: 'input',
          message: '两次输入的密码不一致',
          validate (val, ruleValue) {
            return (ruleValue || '').indexOf(val || '') === 0
          }
        },
        {
          name: 'same',
          value: this.data.password,
          triggers: 'change,password:input',
          message: '两次输入的密码不一致',
          validate (val, ruleValue) {
            return !val || (ruleValue || '') === val
          }
        }
      ]
    }
  }
}
</script>

Async validation

-
Edit this demo on GitHubEdit
<template>
<article class="form-demo">
  <veui-form
    ref="form"
    :data="data"
    :validators="validators"
  >
    <veui-fieldset
      label="预期收入"
      class="salary"
      tip="下限必须小于上限"
      :required="true"
    >
      <veui-field
        field="start"
        name="start"
        :rules="numRequiredRule"
        class="start-field"
      >
        <veui-input
          v-model="data.start"
          class="input"
        />
      </veui-field>
      <veui-span style="margin: 0 4px">
        -
      </veui-span>
      <veui-field
        field="end"
        name="end"
        :rules="numRequiredRule"
      >
        <veui-input
          v-model="data.end"
          class="input"
        />
      </veui-field>
      <veui-span></veui-span>
    </veui-fieldset>

    <template #actions="{ validating }">
      <veui-button
        ui="primary"
        :loading="validating"
        type="submit"
      >
        提交
      </veui-button>
    </template>
  </veui-form>
</article>
</template>

<script>
import {
  Form,
  Fieldset,
  Field,
  Input,
  Button,
  Span
} from 'veui'

export default {
  name: 'demo-form',
  components: {
    'veui-span': Span,
    'veui-input': Input,
    'veui-button': Button,
    'veui-form': Form,
    'veui-field': Field,
    'veui-fieldset': Fieldset
  },
  data () {
    return {
      data: {
        start: 20000,
        end: 10000
      },
      numRequiredRule: [
        {
          name: 'numeric',
          value: true,
          triggers: 'blur,input'
        },
        {
          name: 'required',
          value: true,
          triggers: 'blur,input'
        }
      ],
      validators: [
        {
          fields: ['start', 'end'],
          handler (start, end) {
            if (start == null || end == null) {
              return true
            }

            return new Promise(function (resolve) {
              setTimeout(function () {
                let res = {}
                if (parseInt(start, 10) < 4000) {
                  res.start = {
                    status: 'warning',
                    message: '请提高下限'
                  }
                }
                if (parseInt(start, 10) >= parseInt(end, 10)) {
                  res.end = '上限必须大于下限'
                }
                resolve(Object.keys(res).length ? res : true)
              }, 2000)
            })
          },
          triggers: ['change', 'submit,input']
        }
      ]
    }
  }
}
</script>

<style lang="less" scoped>
.form-demo {
  .salary {
    .input {
      width: 80px;
    }
  }
}
</style>

Before/after validation

Edit this demo on GitHubEdit
<template>
<article class="veui-form-demo">
  <veui-form
    ref="form"
    :data="data"
    :before-validate="beforeValidate"
    :after-validate="afterValidate"
  >
    <veui-field
      field="name"
      name="name"
      label="姓名"
    >
      <veui-input v-model="data.name"/>
    </veui-field>

    <veui-field
      field="phone"
      name="phone"
      label="手机"
    >
      <veui-input
        v-model="data.phone"
        name="phone"
        autocomplete="off"
      />
    </veui-field>

    <template #actions>
      <veui-button
        ui="primary"
        type="submit"
      >提交</veui-button>
    </template>
  </veui-form>
</article>
</template>

<script>
import {
  Form,
  Field,
  Input,
  Button
} from 'veui'
import confirmManager from 'veui/managers/confirm'

export default {
  name: 'demo-form',
  components: {
    'veui-input': Input,
    'veui-button': Button,
    'veui-form': Form,
    'veui-field': Field
  },
  data () {
    return {
      data: {
        name: '曹达华',
        phone: '18888888888'
      }
    }
  },
  methods: {
    beforeValidate () {
      return new Promise((resolve) => {
        confirmManager
          .warn('前置校验通过吗?', '确认', {
            ok: () => {}
          })
          .then((ok) => {
            resolve(ok)
          })
      })
    },
    afterValidate () {
      return new Promise((resolve) => {
        confirmManager
          .warn('后置校验通过吗?', '确认', {
            ok: () => {}
          })
          .then((ok) => {
            resolve(ok)
          })
      })
    }
  }
}
</script>

Abstract fields

Available

  • 门店1
  • 门店2
  • 门店3
  • 门店4

Selected

Please select
Edit this demo on GitHubEdit
<template>
<article>
  <veui-form
    :data="formData"
  >
    <veui-field
      label="门店"
      name="store"
      :rules="[{
        name: 'required', message: '请选择门店', triggers: 'select'
      }]"
    >
      <veui-transfer
        v-model="formData.store"
        :datasource="storeList"
      >
        <template #selected-item-label="{ label, value }">
          <div class="selected-store">
            <span class="store-label">{{ label }}</span>
            <veui-field
              :key="`storeCounts.${value}`"
              :name="`storeCounts.${value}`"
              :rules="[
                { name: 'required', message: `请填写${label}的数量`, triggers: 'change,blur' }
              ]"
              abstract
            >
              <veui-number-input
                v-model="formData.storeCounts[value]"
                class="store-number"
                ui="s"
                :min="1"
              />
            </veui-field>
          </div>
        </template>
      </veui-transfer>
    </veui-field>
  </veui-form>
</article>
</template>

<script>
import { Form, Field, NumberInput, Transfer } from 'veui'

export default {
  components: {
    'veui-form': Form,
    'veui-field': Field,
    'veui-number-input': NumberInput,
    'veui-transfer': Transfer
  },
  data () {
    return {
      disabled: true,
      formData: {
        store: [],
        storeCounts: {}
      },
      storeList: [
        { label: '门店1', value: '1' },
        { label: '门店2', value: '2' },
        { label: '门店3', value: '3' },
        { label: '门店4', value: '4' }
      ]
    }
  }
}
</script>

<style lang="less" scoped>
.selected-store {
  display: flex;
  align-items: center;

  .store-label {
    min-width: 60px;
  }
}
</style>

Native inputs

Edit this demo on GitHubEdit
<template>
<article>
  <veui-form
    :data="formData"
  >
    <veui-field
      label="名称"
      name="name"
      withhold-validity
      :rules="[{ name: 'required', triggers: 'input,blur' }]"
    >
      <template #default="{ invalid, listeners }">
        <input
          v-model="formData.name"
          :class="{
            'demo-invalid': invalid
          }"
          v-on="listeners"
        >
      </template>
    </veui-field>
  </veui-form>
</article>
</template>

<script>
import { Form, Field } from 'veui'

export default {
  components: {
    'veui-form': Form,
    'veui-field': Field
  },
  data () {
    return {
      formData: {
        name: ''
      }
    }
  }
}
</script>

<style lang="less" scoped>
.demo-invalid {
  border: 1px solid #cc1800;
}
</style>

API

Props

NameTypeDefaultDescription
readonlybooleanfalseWhether the internal input component is in read-only state.
disabledbooleanfalseWhether the internal input component is disabled.
dataObject-

Data bound to the form, bound to input components in the form through v-model, and is also the data source for form verification.

validatorsArray<Object>-

Cross validators and async validator. The item type is {fields, validate, triggers}.

NameTypeDescription
fieldsArrayA collection corresponding to the field description of Field. The event will be bound to the input component in the corresponding Field.
validatefunctionCustom validation function, with (data[fields[0]], data[fields[1]], ...) as its parameter, where data refers to the value of the data property of the form. Returns undefined / true for successful validation, and returns {[field]: message, ...} for failed validation messages. See Form › Form validation logic for details.
triggersstring | Array<string>Collection of event names, supporting <fieldName>:<eventName> to trigger validation when the eventName event occurs in the fieldName field.
fieldstriggersEvent binding
['a']['change', 'blur,input,xxx', 'submit']a(change)
['a','b','c']['change', 'blur,input,xxx', 'submit']a(change), b(blur,input,xxx), c(submit)
['a','b','c']'blur'a(blur), b(submit), c(submit)
['a','b','c']'blur,input'a(blur,input), b(blur,input), c(blur,input)
['a']'blur,b:input'a(blur,b:input)
before-validatefunction-Hook before the form enters the validation process, with parameters (data), which is a copy of the form data property value. Supports returning Promise, true or undefined for the return value or Promise.resolve indicates that the process continues, and other return values indicate interrupting the process and triggering the invalid event.
after-validatefunction-Hook triggered after the form is successfully validated and before the submit event is triggered, with parameters (data), which is the same reference as the entry parameter in beforeValidate. Supports returning Promise, true or undefined for the return value or Promise.resolve indicates that the process continues, and other return values indicate interrupting the process and triggering the invalid event.

Slots

NameDescription
default

Can be directly inlined with Fieldset or Field components. There is no default content.

NameTypeDescription
submit() => voidTrigger the form submission.
validatingbooleanWhether the form is currently being validated.
actionsForm operation content, such as "Submit" and "Cancel" buttons. There is no default content. The slot parameter is the same as the default slot.

Events

NameDescription
submit

Triggered after the native submit event, with (data, event) as the callback parameters. For the specific submission process, please refer to Form › Form submission process.

NameTypeDescription
dataObjectA reference to the value of the data property of the form.
eventEventNative event object.
invalid

Triggered when a process in the beforeValidate, validate, or afterValidate flow returns an interrupt, with the return value of the flow function as the parameter (result), indicating the information about the interruption in the flow. The specific submission process is described in Form › Form submission process, and the validate logic is described in Form › Form validation logic.

Methods

NameDescription
submit

Manually submit the form.

function submit(): void
validate

Manually validate the form.

function validate(fieldNames?: Array<string> | null): Promise<true | Record<string, Object>>

Optional parameter fieldNames specifies the fields to validate.

Returns a Promise. Resolves to true if validation passes, and resolves to Record<string, Object> if validation fails, where the key is the name of the field with the error.

clearValidities

Manually clear the validation messages.

function clearValidities(fieldNames?: Array<string> | null): void

Optional parameter fieldNames specifies the fields to clear.

setValidities

Manually set the validation messages.

type InputValidity = {
  status: 'success' | 'warning' | 'error'
  message: string
}

function setValidities(validities: Record<string, string | InputValidity>): void

// Example: add submission errors to the form
this.$refs.form.setValidities({
  name: 'name error',
  email: 'email error'
})

Form submission

Form validation

The form validation is divided into the rule validation of the Field and the validation of the validators.

  1. The rule of the Field is a single-value synchronous validation. See form item for details.
  2. The validators can be multi-value asynchronous validation.
validators: [
  {
    fields: ['start', 'end'],
    validate (start, end) {
      if (start == null || end == null) {
        return true
      }

      if (parseInt(start, 10) >= parseInt(end, 10)) {
        return {
          start: 'The lower limit must be less than the upper limit'
        }
      }
      return true
    },
    triggers: ['change', 'submit,input']
  },
  {
    fields: ['phone'],
    validate (phone) {
      return new Promise(function (resolve) {
        setTimeout(function () {
          let res
          if (phone === '18888888888') {
            res = {
              phone: 'This phone has been registered'
            }
          }
          return resolve(res)
        }, 3000)
      })
    },
    triggers: ['input']
  }
]

Interaction validation

Submission validation

During submission, the failure of one of the validation processes will not cause the entire validation to terminate. The validation information will be integrated after both processes are completed and passed to the invalid event.

Edit this page on GitHubEdit
© Baidu, Inc. 2024