Skip to content
On this page

表单 Form

由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据

基础用法

基础的表单使用,表单项,比如输入框、选择器、开关、单选框、多选框等。

<template>
  <div style="width: 500px">
    <b-form ref="form" :model="formObj" label-width="100px">
      <b-form-item label="姓名">
        <b-input v-model="formObj.name" placeholder="输入姓名"></b-input>
      </b-form-item>
      <b-form-item label="年龄">
        <b-input-number v-model="formObj.age"></b-input-number>
      </b-form-item>
      <b-form-item label="户籍地">
        <b-select v-model="formObj.region" placeholder="请选择户籍地">
          <b-option label="上海" value="shanghai"></b-option>
          <b-option label="北京" value="beijing"></b-option>
          <b-option label="南京" value="nanjing"></b-option>
          <b-option label="徐州" value="xuzhou"></b-option>
        </b-select>
      </b-form-item>
      <b-form-item label="学历">
        <b-radio-group v-model="formObj.edu">
          <b-radio label="高中"></b-radio>
          <b-radio label="大专"></b-radio>
          <b-radio label="本科"></b-radio>
          <b-radio label="硕士"></b-radio>
        </b-radio-group>
      </b-form-item>
      <b-form-item label="爱好">
        <b-checkbox-group v-model="formObj.hobby">
          <b-checkbox label="打游戏" name="hobby"></b-checkbox>
          <b-checkbox label="看电影" name="hobby"></b-checkbox>
          <b-checkbox label="打篮球/运动" name="hobby"></b-checkbox>
          <b-checkbox label="看书" name="hobby"></b-checkbox>
        </b-checkbox-group>
      </b-form-item>
      <b-form-item label="住址">
        <b-input v-model="formObj.address" type="textarea" placeholder="请输入住址..."></b-input>
      </b-form-item>
      <b-form-item>
        <b-button type="primary" @click="onSubmit">提交</b-button>
        <b-button>取消</b-button>
      </b-form-item>
    </b-form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const formObj = ref({
  name: '',
  age: null,
  region: '',
  city: '',
  edu: '',
  hobby: [],
  address: ''
})

function onSubmit() {
  console.log('submit!', formObj.value)
}
</script>
<template>
  <div style="width: 500px">
    <b-form ref="form" :model="formObj" label-width="100px">
      <b-form-item label="姓名">
        <b-input v-model="formObj.name" placeholder="输入姓名"></b-input>
      </b-form-item>
      <b-form-item label="年龄">
        <b-input-number v-model="formObj.age"></b-input-number>
      </b-form-item>
      <b-form-item label="户籍地">
        <b-select v-model="formObj.region" placeholder="请选择户籍地">
          <b-option label="上海" value="shanghai"></b-option>
          <b-option label="北京" value="beijing"></b-option>
          <b-option label="南京" value="nanjing"></b-option>
          <b-option label="徐州" value="xuzhou"></b-option>
        </b-select>
      </b-form-item>
      <b-form-item label="学历">
        <b-radio-group v-model="formObj.edu">
          <b-radio label="高中"></b-radio>
          <b-radio label="大专"></b-radio>
          <b-radio label="本科"></b-radio>
          <b-radio label="硕士"></b-radio>
        </b-radio-group>
      </b-form-item>
      <b-form-item label="爱好">
        <b-checkbox-group v-model="formObj.hobby">
          <b-checkbox label="打游戏" name="hobby"></b-checkbox>
          <b-checkbox label="看电影" name="hobby"></b-checkbox>
          <b-checkbox label="打篮球/运动" name="hobby"></b-checkbox>
          <b-checkbox label="看书" name="hobby"></b-checkbox>
        </b-checkbox-group>
      </b-form-item>
      <b-form-item label="住址">
        <b-input v-model="formObj.address" type="textarea" placeholder="请输入住址..."></b-input>
      </b-form-item>
      <b-form-item>
        <b-button type="primary" @click="onSubmit">提交</b-button>
        <b-button>取消</b-button>
      </b-form-item>
    </b-form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const formObj = ref({
  name: '',
  age: null,
  region: '',
  city: '',
  edu: '',
  hobby: [],
  address: ''
})

function onSubmit() {
  console.log('submit!', formObj.value)
}
</script>

行内表单

表单内容项比较少的情况可以使用行内模式

<template>
  <b-form ref="form" :model="formObj" inline class="demo-form-inline">
    <b-form-item label="姓名">
      <b-input v-model="formObj.name" placeholder="输入姓名"></b-input>
    </b-form-item>
    <b-form-item label="户籍地">
      <b-select v-model="formObj.region" placeholder="请选择户籍地">
        <b-option label="上海" value="shanghai"></b-option>
        <b-option label="北京" value="beijing"></b-option>
        <b-option label="南京" value="nanjing"></b-option>
        <b-option label="徐州" value="xuzhou"></b-option>
      </b-select>
    </b-form-item>
    <b-form-item>
      <b-button type="primary" @click="onSubmit">提交</b-button>
    </b-form-item>
  </b-form>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const formObj = ref({
  name: '',
  region: ''
})

function onSubmit() {
  console.log('submit!', formObj.value)
}
</script>
<template>
  <b-form ref="form" :model="formObj" inline class="demo-form-inline">
    <b-form-item label="姓名">
      <b-input v-model="formObj.name" placeholder="输入姓名"></b-input>
    </b-form-item>
    <b-form-item label="户籍地">
      <b-select v-model="formObj.region" placeholder="请选择户籍地">
        <b-option label="上海" value="shanghai"></b-option>
        <b-option label="北京" value="beijing"></b-option>
        <b-option label="南京" value="nanjing"></b-option>
        <b-option label="徐州" value="xuzhou"></b-option>
      </b-select>
    </b-form-item>
    <b-form-item>
      <b-button type="primary" @click="onSubmit">提交</b-button>
    </b-form-item>
  </b-form>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const formObj = ref({
  name: '',
  region: ''
})

function onSubmit() {
  console.log('submit!', formObj.value)
}
</script>

对齐和尺寸

可以有三种不同的标签对齐方式,纯文字需要包裹label标签

对齐方式
尺寸大小
文字显示
<template>
  <div>
    <b-space>
      对齐方式
      <b-radio-group v-model="labelPosition" type="capsule">
        <b-radio label="left">左对齐</b-radio>
        <b-radio label="right">右对齐</b-radio>
        <b-radio label="top">顶部对齐</b-radio>
      </b-radio-group>
      尺寸大小
      <b-radio-group v-model="size" type="capsule">
        <b-radio label="large">large</b-radio>
        <b-radio label="default">default</b-radio>
        <b-radio label="small">small</b-radio>
        <b-radio label="mini">mini</b-radio>
      </b-radio-group>
      文字显示
      <b-switch v-model="onlyText"></b-switch>
    </b-space>
    <div style="width: 500px; margin-top: 20px">
      <b-form :label-position="labelPosition" label-width="100px" :model="formObj" :size="size">
        <b-form-item label="姓名">
          <b-input v-if="!onlyText" v-model="formObj.name" placeholder="输入姓名"></b-input>
          <label v-else>{{ formObj.name }}</label>
        </b-form-item>
        <b-form-item label="年龄">
          <b-input-number v-if="!onlyText" v-model="formObj.age"></b-input-number>
          <label v-else>{{ formObj.age }}</label>
        </b-form-item>
        <b-form-item label="户籍地">
          <b-select v-if="!onlyText" v-model="formObj.city" placeholder="请选择户籍地">
            <b-option label="上海" value="shanghai"></b-option>
            <b-option label="北京" value="beijing"></b-option>
            <b-option label="南京" value="nanjing"></b-option>
            <b-option label="徐州" value="xuzhou"></b-option>
          </b-select>
          <label v-else>{{ formObj.city }}</label>
        </b-form-item>
        <b-form-item label="学历">
          <b-radio-group v-if="!onlyText" v-model="formObj.edu">
            <b-radio label="高中"></b-radio>
            <b-radio label="大专"></b-radio>
            <b-radio label="本科"></b-radio>
            <b-radio label="硕士"></b-radio>
          </b-radio-group>
          <span v-else>{{ formObj.edu }}</span>
        </b-form-item>
        <b-form-item label="爱好">
          <b-checkbox-group v-if="!onlyText" v-model="formObj.hobby">
            <b-checkbox label="打游戏" name="hobby"></b-checkbox>
            <b-checkbox label="看电影" name="hobby"></b-checkbox>
            <b-checkbox label="打篮球/运动" name="hobby"></b-checkbox>
            <b-checkbox label="看书" name="hobby"></b-checkbox>
          </b-checkbox-group>
          <span v-else>{{ formObj.hobby }}</span>
        </b-form-item>
        <b-form-item label="住址">
          <b-input
            v-if="!onlyText"
            v-model="formObj.address"
            type="textarea"
            placeholder="请输入住址..."
          ></b-input>
          <span v-else>{{ formObj.address }}</span>
        </b-form-item>
        <!-- <b-form-item label="进度">
        <b-slider></b-slider>
      </b-form-item>
      <b-form-item label="颜色">
        <b-color-picker></b-color-picker>
      </b-form-item>
      <b-form-item label="评分">
        <b-rate></b-rate>
      </b-form-item>
      <b-form-item label="日期选择器">
        <b-date-picker></b-date-picker>
      </b-form-item>
      <b-form-item label="时间选择器">
        <b-time-picker></b-time-picker>
      </b-form-item>
      <b-form-item label="开关">
        <b-switch></b-switch>
      </b-form-item> -->
        <b-form-item v-if="!onlyText">
          <b-button type="primary">提交</b-button>
          <b-button>取消</b-button>
        </b-form-item>
      </b-form>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const labelPosition = ref('right')
const size = ref('default')
const onlyText = ref(false)

const formObj = ref({
  name: '张三',
  age: 18,
  city: 'xuzhou',
  edu: '高中',
  hobby: ['打游戏', '看电影'],
  address: '徐州市鼓楼区'
})
</script>
<template>
  <div>
    <b-space>
      对齐方式
      <b-radio-group v-model="labelPosition" type="capsule">
        <b-radio label="left">左对齐</b-radio>
        <b-radio label="right">右对齐</b-radio>
        <b-radio label="top">顶部对齐</b-radio>
      </b-radio-group>
      尺寸大小
      <b-radio-group v-model="size" type="capsule">
        <b-radio label="large">large</b-radio>
        <b-radio label="default">default</b-radio>
        <b-radio label="small">small</b-radio>
        <b-radio label="mini">mini</b-radio>
      </b-radio-group>
      文字显示
      <b-switch v-model="onlyText"></b-switch>
    </b-space>
    <div style="width: 500px; margin-top: 20px">
      <b-form :label-position="labelPosition" label-width="100px" :model="formObj" :size="size">
        <b-form-item label="姓名">
          <b-input v-if="!onlyText" v-model="formObj.name" placeholder="输入姓名"></b-input>
          <label v-else>{{ formObj.name }}</label>
        </b-form-item>
        <b-form-item label="年龄">
          <b-input-number v-if="!onlyText" v-model="formObj.age"></b-input-number>
          <label v-else>{{ formObj.age }}</label>
        </b-form-item>
        <b-form-item label="户籍地">
          <b-select v-if="!onlyText" v-model="formObj.city" placeholder="请选择户籍地">
            <b-option label="上海" value="shanghai"></b-option>
            <b-option label="北京" value="beijing"></b-option>
            <b-option label="南京" value="nanjing"></b-option>
            <b-option label="徐州" value="xuzhou"></b-option>
          </b-select>
          <label v-else>{{ formObj.city }}</label>
        </b-form-item>
        <b-form-item label="学历">
          <b-radio-group v-if="!onlyText" v-model="formObj.edu">
            <b-radio label="高中"></b-radio>
            <b-radio label="大专"></b-radio>
            <b-radio label="本科"></b-radio>
            <b-radio label="硕士"></b-radio>
          </b-radio-group>
          <span v-else>{{ formObj.edu }}</span>
        </b-form-item>
        <b-form-item label="爱好">
          <b-checkbox-group v-if="!onlyText" v-model="formObj.hobby">
            <b-checkbox label="打游戏" name="hobby"></b-checkbox>
            <b-checkbox label="看电影" name="hobby"></b-checkbox>
            <b-checkbox label="打篮球/运动" name="hobby"></b-checkbox>
            <b-checkbox label="看书" name="hobby"></b-checkbox>
          </b-checkbox-group>
          <span v-else>{{ formObj.hobby }}</span>
        </b-form-item>
        <b-form-item label="住址">
          <b-input
            v-if="!onlyText"
            v-model="formObj.address"
            type="textarea"
            placeholder="请输入住址..."
          ></b-input>
          <span v-else>{{ formObj.address }}</span>
        </b-form-item>
        <!-- <b-form-item label="进度">
        <b-slider></b-slider>
      </b-form-item>
      <b-form-item label="颜色">
        <b-color-picker></b-color-picker>
      </b-form-item>
      <b-form-item label="评分">
        <b-rate></b-rate>
      </b-form-item>
      <b-form-item label="日期选择器">
        <b-date-picker></b-date-picker>
      </b-form-item>
      <b-form-item label="时间选择器">
        <b-time-picker></b-time-picker>
      </b-form-item>
      <b-form-item label="开关">
        <b-switch></b-switch>
      </b-form-item> -->
        <b-form-item v-if="!onlyText">
          <b-button type="primary">提交</b-button>
          <b-button>取消</b-button>
        </b-form-item>
      </b-form>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const labelPosition = ref('right')
const size = ref('default')
const onlyText = ref(false)

const formObj = ref({
  name: '张三',
  age: 18,
  city: 'xuzhou',
  edu: '高中',
  hobby: ['打游戏', '看电影'],
  address: '徐州市鼓楼区'
})
</script>

没有label显示

<template>
  <div style="width: 500px">
    <b-form :model="formObj">
      <b-form-item>
        <b-input v-model="formObj.username" placeholder="输入用户名"></b-input>
      </b-form-item>
      <b-form-item>
        <b-input v-model="formObj.password" placeholder="输入用户名" type="password"></b-input>
      </b-form-item>
      <b-form-item>
        <b-button type="primary" style="width: 100%">登录</b-button>
      </b-form-item>
    </b-form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const formObj = ref({
  username: '',
  password: ''
})
</script>
<template>
  <div style="width: 500px">
    <b-form :model="formObj">
      <b-form-item>
        <b-input v-model="formObj.username" placeholder="输入用户名"></b-input>
      </b-form-item>
      <b-form-item>
        <b-input v-model="formObj.password" placeholder="输入用户名" type="password"></b-input>
      </b-form-item>
      <b-form-item>
        <b-button type="primary" style="width: 100%">登录</b-button>
      </b-form-item>
    </b-form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const formObj = ref({
  username: '',
  password: ''
})
</script>

表单校验

提供基础的校验规则,校验规则参考 async-validator

<template>
  <div style="width: 500px">
    <b-form ref="ruleForm" :model="formObj" status-icon label-width="100px" :rules="ruleValidate">
      <b-form-item prop="name" label="名称">
        <b-input v-model="formObj.name" placeholder="用户名"></b-input>
      </b-form-item>
      <b-form-item prop="mail" label="邮箱">
        <b-input v-model="formObj.mail" placeholder="邮箱" clearable></b-input>
      </b-form-item>
      <b-row>
        <b-col :span="12">
          <b-form-item prop="age" label="年龄">
            <b-input-number v-model="formObj.age" style="width: 100%"></b-input-number>
          </b-form-item>
        </b-col>
        <b-col :span="12">
          <b-form-item label="户籍地" prop="region">
            <b-select v-model="formObj.region" placeholder="请选择户籍地" clearable>
              <b-option label="上海" value="shanghai"></b-option>
              <b-option label="北京" value="beijing"></b-option>
              <b-option label="南京" value="nanjing"></b-option>
              <b-option label="徐州" value="xuzhou"></b-option>
            </b-select>
          </b-form-item>
        </b-col>
      </b-row>
      <b-form-item label="出生日期" prop="birthday">
        <b-date-picker
          v-model="formObj.birthday"
          type="date"
          placeholder="出生日期"
        ></b-date-picker>
      </b-form-item>
      <b-form-item label="爱好" prop="hobby">
        <b-checkbox-group v-model="formObj.hobby">
          <b-checkbox label="打游戏" name="hobby"></b-checkbox>
          <b-checkbox label="看电影" name="hobby"></b-checkbox>
          <b-checkbox label="打篮球/运动" name="hobby"></b-checkbox>
          <b-checkbox label="看书" name="hobby"></b-checkbox>
        </b-checkbox-group>
      </b-form-item>
      <b-form-item label="性别" prop="sex">
        <b-radio-group v-model="formObj.sex">
          <b-radio label="男" value="male"></b-radio>
          <b-radio label="女" value="female"></b-radio>
        </b-radio-group>
      </b-form-item>
      <b-form-item label="状态" prop="status">
        <b-switch v-model="formObj.status" true-value="enable" false-value="disable" size="large">
          <template #open><span>启用</span></template>
          <template #close><span>禁用</span></template>
        </b-switch>
      </b-form-item>
      <b-form-item>
        <b-button type="primary" @click="submitForm">提交</b-button>
        <b-button @click="resetForm">重置</b-button>
      </b-form-item>
    </b-form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const ruleValidate = {
  name: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
  region: [{ required: true, message: '户籍地不能为空', trigger: 'change' }],
  age: [
    { required: true, type: 'number', message: '年龄不为空', trigger: 'change' },
    { type: 'number', min: 18, trigger: 'change', message: '年龄必须在18以上' }
  ],
  hobby: [{ type: 'array', required: true, message: '请至少选择一个爱好', trigger: 'change' }],
  sex: [{ required: true, message: '性别必选', trigger: 'change' }],
  birthday: [{ required: true, type: 'date', message: '出生日期必选', trigger: 'blur' }],
  mail: [
    { required: true, message: '邮箱不能为空', trigger: 'blur' },
    { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
  ]
}

const ruleForm = ref(null)

const formObj = ref({
  name: '',
  age: null,
  mail: '',
  region: '',
  hobby: [],
  sex: '',
  status: 'disable',
  birthday: ''
})

function submitForm() {
  ruleForm.value?.validate(valid => {
    if (valid) {
      alert('submit!')
    } else {
      console.log('error submit!!')
      return false
    }
  })
}
function resetForm() {
  ruleForm.value?.resetFields()
}
</script>
<template>
  <div style="width: 500px">
    <b-form ref="ruleForm" :model="formObj" status-icon label-width="100px" :rules="ruleValidate">
      <b-form-item prop="name" label="名称">
        <b-input v-model="formObj.name" placeholder="用户名"></b-input>
      </b-form-item>
      <b-form-item prop="mail" label="邮箱">
        <b-input v-model="formObj.mail" placeholder="邮箱" clearable></b-input>
      </b-form-item>
      <b-row>
        <b-col :span="12">
          <b-form-item prop="age" label="年龄">
            <b-input-number v-model="formObj.age" style="width: 100%"></b-input-number>
          </b-form-item>
        </b-col>
        <b-col :span="12">
          <b-form-item label="户籍地" prop="region">
            <b-select v-model="formObj.region" placeholder="请选择户籍地" clearable>
              <b-option label="上海" value="shanghai"></b-option>
              <b-option label="北京" value="beijing"></b-option>
              <b-option label="南京" value="nanjing"></b-option>
              <b-option label="徐州" value="xuzhou"></b-option>
            </b-select>
          </b-form-item>
        </b-col>
      </b-row>
      <b-form-item label="出生日期" prop="birthday">
        <b-date-picker
          v-model="formObj.birthday"
          type="date"
          placeholder="出生日期"
        ></b-date-picker>
      </b-form-item>
      <b-form-item label="爱好" prop="hobby">
        <b-checkbox-group v-model="formObj.hobby">
          <b-checkbox label="打游戏" name="hobby"></b-checkbox>
          <b-checkbox label="看电影" name="hobby"></b-checkbox>
          <b-checkbox label="打篮球/运动" name="hobby"></b-checkbox>
          <b-checkbox label="看书" name="hobby"></b-checkbox>
        </b-checkbox-group>
      </b-form-item>
      <b-form-item label="性别" prop="sex">
        <b-radio-group v-model="formObj.sex">
          <b-radio label="男" value="male"></b-radio>
          <b-radio label="女" value="female"></b-radio>
        </b-radio-group>
      </b-form-item>
      <b-form-item label="状态" prop="status">
        <b-switch v-model="formObj.status" true-value="enable" false-value="disable" size="large">
          <template #open><span>启用</span></template>
          <template #close><span>禁用</span></template>
        </b-switch>
      </b-form-item>
      <b-form-item>
        <b-button type="primary" @click="submitForm">提交</b-button>
        <b-button @click="resetForm">重置</b-button>
      </b-form-item>
    </b-form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const ruleValidate = {
  name: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
  region: [{ required: true, message: '户籍地不能为空', trigger: 'change' }],
  age: [
    { required: true, type: 'number', message: '年龄不为空', trigger: 'change' },
    { type: 'number', min: 18, trigger: 'change', message: '年龄必须在18以上' }
  ],
  hobby: [{ type: 'array', required: true, message: '请至少选择一个爱好', trigger: 'change' }],
  sex: [{ required: true, message: '性别必选', trigger: 'change' }],
  birthday: [{ required: true, type: 'date', message: '出生日期必选', trigger: 'blur' }],
  mail: [
    { required: true, message: '邮箱不能为空', trigger: 'blur' },
    { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
  ]
}

const ruleForm = ref(null)

const formObj = ref({
  name: '',
  age: null,
  mail: '',
  region: '',
  hobby: [],
  sex: '',
  status: 'disable',
  birthday: ''
})

function submitForm() {
  ruleForm.value?.validate(valid => {
    if (valid) {
      alert('submit!')
    } else {
      console.log('error submit!!')
      return false
    }
  })
}
function resetForm() {
  ruleForm.value?.resetFields()
}
</script>

自定义校验规则

可以自定义校验函数来实现更多的校验判定

<template>
  <div style="width: 500px">
    <b-form
      ref="ruleFormRef"
      :model="ruleForm"
      status-icon
      :rules="rules"
      label-width="100px"
      class="demo-ruleForm"
    >
      <b-form-item label="密码" prop="pass">
        <b-input v-model="ruleForm.pass" type="password" autocomplete="off"></b-input>
      </b-form-item>
      <b-form-item label="确认密码" prop="checkPass">
        <b-input v-model="ruleForm.checkPass" type="password" autocomplete="off"></b-input>
      </b-form-item>
      <b-form-item label="年龄" prop="age">
        <b-input v-model.number="ruleForm.age" type="number"></b-input>
      </b-form-item>
      <b-form-item>
        <b-button type="primary" @click="submitForm">提交</b-button>
        <b-button @click="resetForm">重置</b-button>
      </b-form-item>
    </b-form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const checkAge = (rule, value, callback) => {
  if (!value) {
    return callback(new Error('年龄不能为空'))
  }
  setTimeout(() => {
    if (!Number.isInteger(value)) {
      callback(new Error('请输入数字值'))
    } else {
      if (value < 18) {
        callback(new Error('必须年满18岁'))
      } else {
        callback()
      }
    }
  }, 1000)
}
const validatePass = (rule, value, callback) => {
  if (value === '') {
    callback(new Error('请输入密码'))
  } else {
    if (ruleForm.value.checkPass !== '') {
      ruleFormRef.value?.validateField('checkPass')
    }
    callback()
  }
}
const validatePass2 = (rule, value, callback) => {
  if (value === '') {
    callback(new Error('请再次输入密码'))
  } else if (value !== ruleForm.value.pass) {
    callback(new Error('两次输入密码不一致!'))
  } else {
    callback()
  }
}

const ruleFormRef = ref(null)

const rules = ref({
  pass: [{ validator: validatePass, trigger: 'blur' }],
  checkPass: [{ validator: validatePass2, trigger: 'blur' }],
  age: [{ validator: checkAge, trigger: 'blur' }]
})

const ruleForm = ref({
  pass: '',
  checkPass: '',
  age: ''
})

function submitForm() {
  ruleFormRef.value?.validate(valid => {
    if (valid) {
      alert('submit!')
    } else {
      console.log('error submit!!')
      return false
    }
  })
}
function resetForm() {
  ruleFormRef.value?.resetFields()
}
</script>
<template>
  <div style="width: 500px">
    <b-form
      ref="ruleFormRef"
      :model="ruleForm"
      status-icon
      :rules="rules"
      label-width="100px"
      class="demo-ruleForm"
    >
      <b-form-item label="密码" prop="pass">
        <b-input v-model="ruleForm.pass" type="password" autocomplete="off"></b-input>
      </b-form-item>
      <b-form-item label="确认密码" prop="checkPass">
        <b-input v-model="ruleForm.checkPass" type="password" autocomplete="off"></b-input>
      </b-form-item>
      <b-form-item label="年龄" prop="age">
        <b-input v-model.number="ruleForm.age" type="number"></b-input>
      </b-form-item>
      <b-form-item>
        <b-button type="primary" @click="submitForm">提交</b-button>
        <b-button @click="resetForm">重置</b-button>
      </b-form-item>
    </b-form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const checkAge = (rule, value, callback) => {
  if (!value) {
    return callback(new Error('年龄不能为空'))
  }
  setTimeout(() => {
    if (!Number.isInteger(value)) {
      callback(new Error('请输入数字值'))
    } else {
      if (value < 18) {
        callback(new Error('必须年满18岁'))
      } else {
        callback()
      }
    }
  }, 1000)
}
const validatePass = (rule, value, callback) => {
  if (value === '') {
    callback(new Error('请输入密码'))
  } else {
    if (ruleForm.value.checkPass !== '') {
      ruleFormRef.value?.validateField('checkPass')
    }
    callback()
  }
}
const validatePass2 = (rule, value, callback) => {
  if (value === '') {
    callback(new Error('请再次输入密码'))
  } else if (value !== ruleForm.value.pass) {
    callback(new Error('两次输入密码不一致!'))
  } else {
    callback()
  }
}

const ruleFormRef = ref(null)

const rules = ref({
  pass: [{ validator: validatePass, trigger: 'blur' }],
  checkPass: [{ validator: validatePass2, trigger: 'blur' }],
  age: [{ validator: checkAge, trigger: 'blur' }]
})

const ruleForm = ref({
  pass: '',
  checkPass: '',
  age: ''
})

function submitForm() {
  ruleFormRef.value?.validate(valid => {
    if (valid) {
      alert('submit!')
    } else {
      console.log('error submit!!')
      return false
    }
  })
}
function resetForm() {
  ruleFormRef.value?.resetFields()
}
</script>

动态增加校验

可以动态的配置校验规则

<template>
  <div style="width: 500px">
    <b-form ref="formRef" :model="dynamicValidateForm" label-width="100px" class="demo-dynamic">
      <b-form-item
        v-for="(domain, index) in dynamicValidateForm.domains"
        :key="domain.key"
        :label="'域名' + index"
        :prop="'domains.' + index + '.value'"
        :rules="{
          required: true,
          message: '域名不能为空',
          trigger: 'blur'
        }"
      >
        <div flex="box:last">
          <b-input v-model="domain.value"></b-input>
          <b-button @click="removeDomain(domain)">删除</b-button>
        </div>
      </b-form-item>
      <b-form-item>
        <b-button type="primary" @click="submitForm">提交</b-button>
        <b-button @click="addDomain">新增域名</b-button>
        <b-button @click="resetForm">重置</b-button>
      </b-form-item>
    </b-form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const dynamicValidateForm = ref({
  domains: [
    {
      value: ''
    }
  ]
})
const formRef = ref(null)

function submitForm() {
  formRef.value?.validate(valid => {
    if (valid) {
      alert('submit!')
    } else {
      console.log('error submit!!')
      return false
    }
  })
}
function resetForm() {
  formRef.value?.resetFields()
}
function removeDomain(item) {
  const index = dynamicValidateForm.value.domains.indexOf(item)
  if (index !== -1) {
    dynamicValidateForm.value.domains.splice(index, 1)
  }
}
function addDomain() {
  dynamicValidateForm.value.domains.push({
    value: '',
    key: Date.now()
  })
}
</script>
<template>
  <div style="width: 500px">
    <b-form ref="formRef" :model="dynamicValidateForm" label-width="100px" class="demo-dynamic">
      <b-form-item
        v-for="(domain, index) in dynamicValidateForm.domains"
        :key="domain.key"
        :label="'域名' + index"
        :prop="'domains.' + index + '.value'"
        :rules="{
          required: true,
          message: '域名不能为空',
          trigger: 'blur'
        }"
      >
        <div flex="box:last">
          <b-input v-model="domain.value"></b-input>
          <b-button @click="removeDomain(domain)">删除</b-button>
        </div>
      </b-form-item>
      <b-form-item>
        <b-button type="primary" @click="submitForm">提交</b-button>
        <b-button @click="addDomain">新增域名</b-button>
        <b-button @click="resetForm">重置</b-button>
      </b-form-item>
    </b-form>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const dynamicValidateForm = ref({
  domains: [
    {
      value: ''
    }
  ]
})
const formRef = ref(null)

function submitForm() {
  formRef.value?.validate(valid => {
    if (valid) {
      alert('submit!')
    } else {
      console.log('error submit!!')
      return false
    }
  })
}
function resetForm() {
  formRef.value?.resetFields()
}
function removeDomain(item) {
  const index = dynamicValidateForm.value.domains.indexOf(item)
  if (index !== -1) {
    dynamicValidateForm.value.domains.splice(index, 1)
  }
}
function addDomain() {
  dynamicValidateForm.value.domains.push({
    value: '',
    key: Date.now()
  })
}
</script>

Form Props

参数说明类型可选值默认值
model表单数据对象object
rules表单验证规则object
inline行内表单模式booleanfalse
label-position标签的位置,如果值为 left 或者 right 时,则需要设置 label-widthright/left/topright
label-width表单域标签的宽度,例如 '50px'。作为 Form 直接子元素的 form-item 会继承该值。支持 auto。
label-suffix表单域标签的后缀string
hide-required-asterisk是否隐藏必填字段的标签旁边的红色*booleanfalse
show-message是否显示校验错误信息booleantrue
inline-message是否以行内形式展示校验信息,此时右侧需要留出校验信息的显示宽度才可以正常使用booleanfalse
status-icon是否在输入框中显示校验结果反馈图标booleanfalse
validate-on-rule-change是否在 rules 属性改变后立即触发一次验证booleantrue
size用于控制该表单内组件的尺寸stringlarge,default,small,mini
disabled是否禁用该表单内的所有组件。若设置为 true,则表单内组件上的 disabled 属性不再生效false

Form Methods

方法名说明返回值
validate对整个表单进行校验的方法,参数为一个回调函数。该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则会返回一个 promiseFunction(callback: Function(boolean, object))
validateField对部分表单字段进行校验的方法Function(props: array、string, callback: Function(errorMessage: string))
resetFields对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
clearValidate移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果Function(props: array 、 string)

Form Events

方法名说明返回值
validate任一表单项被校验后触发被校验的表单项 prop 值,校验是否通过,错误消息(如果存在)

FormItem Props

参数说明类型可选值默认值
prop表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的string传入 Form 组件的 model 中的字段
label标签文本string
label-width表单域标签的的宽度,例如 '80px'。支持 auto。string
required是否必填,如不设置,则会根据校验规则自动生成booleanfalse
rules表单验证规则object
error表单域验证错误信息, 设置该值会使表单验证状态变为error,并显示该错误信息string
show-message是否显示校验错误信息booleantrue
inline-message以行内形式展示校验信息booleanfalse
size用于控制该表单域下组件的尺寸stringlarge,default,small,mini

FormItem Slot

名称说明
default默认内容
label标签文本的内容

FormItem Scoped Slot

名称说明
error自定义表单校验信息的显示方式,参数为

FormItem Methods

名称说明
resetField对该表单项进行重置,将其值重置为初始值并移除校验结果
clearValidate移除该表单项的校验结果