Skip to content

FilterForm 筛选表单

筛选表单,基于z-form封装。

TIP

  1. 如果表单项组件支持placeholderclearablefilterable等属性,会被默认配置
  2. 表单响应式默认配置为{ xl: 6, lg: 8, md: 8, sm: 12, xs: 24 }

基础用法

  • 传入columns定义表单,modelValue为表单数据,options为数据配置项
  • 事件使用on+事件名
  • 表单项组件属性直接在column项中配置即可
  • FormItem组件属性(表单项装饰组件)属性配置在formItemProps字段中,有些字段为了方便使用,直接配置在column项中也可生效(如:labelrequiredmessage等)
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'

const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})

const options = {
  gender: [
    { label: '男', value: '1' },
    { label: '女', value: '2' },
  ],
}

const columns = [
  {
    component: 'input',
    field: 'name',
    label: '名字',
    onInput: (val: string) => {
      console.log(val, 'input event')
    },
    onChange: (val: string) => {
      console.log(val, 'change event')
    },
  },
  {
    component: 'select',
    field: 'gender',
    label: '性别',
    onChange: (val: string) => {
      console.log(val, 'change event')
    },
    onFocus: () => {
      console.log('focus event')
    },
  },
  {
    component: 'el-date-picker',
    field: 'time',
    label: '出生日期',
    fieldProps: {
      type: 'daterange',
      startPlaceholder: '开始日期',
      endPlaceholder: '结束日期',
    },
    onChange: (val: string) => {
      console.log(val, 'change event')
    },
  },
]

function handleSearch() {
  console.log(formData.value, 'search')
}

function handleReset() {
  console.log(formData.value, 'reset')
}
</script>

<template>
  <z-filter-form
    ref="formRef"
    v-model="formData"
    :options="options"
    :columns="columns"
    size="small"
    label-width="80px"
    @search="handleSearch"
    @reset="handleReset"
  />
</template>

校验

  • columns表单项中添加required字段,或者formItemProps中设置required字段,即可设置必填,校验信息会根据label自动生成也可自定义。
  • z-filter-form传入rules字段,可以定义表单校验规则。
  • columns表单项配置rules,可以定义当前表单项校验规则。
<script lang="ts" setup>
import { ref } from 'vue'

const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})

const options = {
  gender: [
    { label: '男', value: '1' },
    { label: '女', value: '2' },
  ],
}

const rules = {
  time: [{ required: true, message: '出生日期必选' }],
}

const columns = [
  {
    component: 'input',
    field: 'name',
    label: '姓名',
    required: true,
    message: '请将姓名填写完整',
  },
  {
    component: 'select',
    field: 'gender',
    formItemProps: {
      required: true,
      label: '性别',
    },
  },
  {
    component: 'el-date-picker',
    field: 'time',
    label: '出生日期',
    rules: {
      required: true,
      message: '出生日期必选',
    },
    fieldProps: {
      type: 'daterange',
      startPlaceholder: '开始日期',
      endPlaceholder: '结束日期',
    },
  },
]
</script>

<template>
  <z-filter-form
    ref="formRef"
    v-model="formData"
    :options="options"
    :columns="columns"
    :rules="rules"
    size="small"
    label-width="80px"
  />
</template>

表单项自定义

我们可以使用slotrender自定义表单项内容。

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

const formRef = ref()
const formData = ref({
  name: '',
  age: '',
  height: '身高自定义',
})

const columns = [
  {
    component: 'input',
    field: 'name',
    label: '姓名',
  },
  {
    slot: 'ageSlot',
    label: '年龄',
  },
  {
    render: () => h('span', {}, formData.value.height),
    label: '身高',
  },
]
</script>

<template>
  <z-filter-form
    ref="formRef"
    v-model="formData"
    :columns="columns"
    size="small"
    label-width="80px"
  >
    <template #ageSlot>
      <el-input v-model="formData.age" placeholder="请输入年龄" clearable />
    </template>
  </z-filter-form>
</template>

label、error自定义

labelerror支持传入字符串、render函数或拼接Slot的字符串

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

const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})

const options = {
  gender: [
    { label: '男', value: '1' },
    { label: '女', value: '2' },
  ],
}

const columns = [
  {
    component: 'input',
    field: 'name',
    label: () => h('span', {}, '姓名'),
    required: true,
    error: 'error message',
  },
  {
    component: 'select',
    field: 'gender',
    label: 'labelSlot',
    required: true,
    error: h('span', {}, 'errorSlot'),
  },
  {
    component: 'el-date-picker',
    field: 'time',
    label: '出生日期',
    required: true,
    error: 'errorSlot',
    fieldProps: {
      type: 'daterange',
      startPlaceholder: '开始日期',
      endPlaceholder: '结束日期',
    },
  },
]
</script>

<template>
  <z-filter-form
    ref="formRef"
    v-model="formData"
    :options="options"
    :columns="columns"
    size="small"
    label-width="80px"
  >
    <template #labelSlot>
      <span>性别</span>
    </template>
    <template #errorSlot>
      <span>出生日期必填</span>
    </template>
  </z-filter-form>
</template>

联动

使用hide配置表单项显隐

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

const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})

const options = {
  gender: [
    { label: '男', value: '1' },
    { label: '女', value: '2' },
  ],
}

const columns = [
  {
    component: 'input',
    field: 'name',
    label: '姓名',
  },
  {
    component: 'select',
    field: 'gender',
    label: '性别',
  },
  {
    component: 'el-date-picker',
    field: 'time',
    label: '出生日期',
    hide: () => !formData.value.gender,
    fieldProps: {
      type: 'daterange',
      startPlaceholder: '开始日期',
      endPlaceholder: '结束日期',
    },
  },
]
</script>

<template>
  <z-filter-form
    ref="formRef"
    v-model="formData"
    :options="options"
    :columns="columns"
    size="small"
    label-width="80px"
  />
</template>

操作按钮

按钮操作会有searchreset事件,已经内置重置操作和校验操作

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'

const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})

const options = {
  gender: [
    { label: '男', value: '1' },
    { label: '女', value: '2' },
  ],
}

const columns = [
  {
    component: 'input',
    field: 'name',
    label: '姓名',
    required: true,
  },
  {
    component: 'select',
    field: 'gender',
    label: '性别',
    required: true,
  },
  {
    component: 'el-date-picker',
    field: 'time',
    label: '出生日期',
    required: true,
    fieldProps: {
      type: 'daterange',
      startPlaceholder: '开始日期',
      endPlaceholder: '结束日期',
    },
  },
]

function handleSearch() {
  console.log(formData.value, 'formData')
}

function handleReset() {
  console.log(formData.value, 'formData')
}
</script>

<template>
  <z-filter-form
    ref="formRef"
    v-model="formData"
    :options="options"
    :columns="columns"
    size="small"
    label-width="80px"
    @search="handleSearch"
    @reset="handleReset"
  />
</template>

设置searchButtonLabelresetButtonLabelsearchButtonLoadingresetButtonLoading来设置按钮文字、加载状态。

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'

const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})
const searchButtonLoading = ref(false)
const resetButtonLoading = ref(false)

const options = {
  gender: [
    { label: '男', value: '1' },
    { label: '女', value: '2' },
  ],
}

const columns = [
  {
    component: 'input',
    field: 'name',
    label: '姓名',
    required: true,
  },
  {
    component: 'select',
    field: 'gender',
    label: '性别',
    required: true,
  },
  {
    component: 'el-date-picker',
    field: 'time',
    label: '出生日期',
    required: true,
    fieldProps: {
      type: 'daterange',
      startPlaceholder: '开始日期',
      endPlaceholder: '结束日期',
    },
  },
]

async function handleSearch() {
  searchButtonLoading.value = true
  await delay(200)
  searchButtonLoading.value = false
  console.log(formData.value, 'formData')
}

async function handleReset() {
  resetButtonLoading.value = true
  await delay(200)
  resetButtonLoading.value = false
  console.log(formData.value, 'formData')
}

function delay(time: number) {
  return new Promise((resolve) => {
    setTimeout(resolve, time)
  })
}
</script>

<template>
  <z-filter-form
    ref="formRef"
    v-model="formData"
    :options="options"
    :columns="columns"
    size="small"
    label-width="80px"
    search-button-label="点击查询"
    reset-button-label="点击重置"
    :search-button-loading="searchButtonLoading"
    :reset-button-loading="resetButtonLoading"
    @search="handleSearch"
    @reset="handleReset"
  />
</template>

设置searchButtonPropsresetButtonProps来设置按钮文字、加载状态。

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { reactive, ref } from 'vue'

const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})
const searchButtonProps = reactive({
  loading: false,
  label: '点击查询',
  type: 'primary',
})
const resetButtonProps = reactive({
  loading: false,
  label: '点击重置',
  type: 'danger',
})

const options = {
  gender: [
    { label: '男', value: '1' },
    { label: '女', value: '2' },
  ],
}

const columns = [
  {
    component: 'input',
    field: 'name',
    label: '姓名',
    required: true,
  },
  {
    component: 'select',
    field: 'gender',
    label: '性别',
    required: true,
  },
  {
    component: 'el-date-picker',
    field: 'time',
    label: '出生日期',
    required: true,
    fieldProps: {
      type: 'daterange',
      startPlaceholder: '开始日期',
      endPlaceholder: '结束日期',
    },
  },
]

async function handleSearch() {
  searchButtonProps.loading = true
  await delay(200)
  searchButtonProps.loading = false
  console.log(formData.value, 'formData')
}

async function handleReset() {
  resetButtonProps.loading = true
  await delay(200)
  resetButtonProps.loading = false
  console.log(formData.value, 'formData')
}

function delay(time: number) {
  return new Promise((resolve) => {
    setTimeout(resolve, time)
  })
}
</script>

<template>
  <z-filter-form
    ref="formRef"
    v-model="formData"
    :options="options"
    :columns="columns"
    size="small"
    label-width="80px"
    :search-button-props="searchButtonProps"
    :reset-button-props="resetButtonProps"
    @search="handleSearch"
    @reset="handleReset"
  />
</template>

通过formOperation插槽或render函数自定义操作按钮。

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { h, ref } from 'vue'

const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})

const options = {
  gender: [
    { label: '男', value: '1' },
    { label: '女', value: '2' },
  ],
}

const columns = [
  {
    component: 'input',
    field: 'name',
    label: '姓名',
    required: true,
  },
  {
    component: 'select',
    field: 'gender',
    label: '性别',
    required: true,
  },
  {
    component: 'el-date-picker',
    field: 'time',
    label: '出生日期',
    required: true,
    fieldProps: {
      type: 'daterange',
      startPlaceholder: '开始日期',
      endPlaceholder: '结束日期',
    },
  },
]

function handleSearch() {
  formRef.value.validate((val: string) => {
    if (val)
      console.log(formData.value, 'formData')
  })
}

function handleReset() {
  formRef.value.resetFields()
}

function renderOperation() {
  return h('span', {}, '查询')
}
</script>

<template>
  <z-filter-form
    ref="formRef"
    v-model="formData"
    :options="options"
    :columns="columns"
    size="small"
    label-width="80px"
  >
    <template #formOperation>
      <el-button type="primary" @click="handleSearch">
        搜索
      </el-button>
      <el-button type="warning" @click="handleReset">
        重置
      </el-button>
    </template>
  </z-filter-form>

  <z-filter-form
    ref="formRef"
    v-model="formData"
    :options="options"
    :columns="columns"
    size="small"
    label-width="80px"
    :render-operation="renderOperation"
  />
</template>

默认收起

配置collapsedfalse,表单会默认收起

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

const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})

const options = {
  gender: [
    { label: '男', value: '1' },
    { label: '女', value: '2' },
  ],
}

const columns = [
  {
    component: 'input',
    field: 'name',
    label: '姓名',
  },
  {
    component: 'select',
    field: 'gender',
    label: '性别',
  },
  {
    component: 'el-date-picker',
    field: 'time',
    label: '出生日期',
    fieldProps: {
      type: 'daterange',
      startPlaceholder: '开始日期',
      endPlaceholder: '结束日期',
    },
  },
]
</script>

<template>
  <z-filter-form
    ref="formRef"
    v-model="formData"
    :options="options"
    :columns="columns"
    size="small"
    label-width="80px"
    :collapsed="false"
  />
</template>

z-filter-form属性

属性名说明类型默认值
modelValue表单数据对象object
collapsed表单默认展开收起booleantrue
searchButtonProps查询按钮属性配置object
searchButtonLabel查询按钮文案string查询
searchButtonLoading查询按钮加载状态boolean
resetButtonProps重置按钮属性配置object
resetButtonLabel重置按钮文案string重置
resetButtonLoading重置按钮加载状态boolean
rules表单验证规则object
label-position表单域标签的位置, 当设置为 leftright 时,则也需要设置 label-width 属性enumright
label-width标签的长度,例如 '50px'。 作为 Form 直接子元素的 form-item 会继承该值。 可以使用 autostring / number''
label-suffix表单域标签的后缀string''
hide-required-asterisk是否隐藏必填字段标签旁边的红色星号。booleanfalse
require-asterisk-position星号的位置。left / rightleft
show-message是否显示校验错误信息booleantrue
inline-message是否以行内形式展示校验信息booleanfalse
status-icon是否在输入框中显示校验结果反馈图标booleanfalse
validate-on-rule-change是否在 rules 属性改变后立即触发一次验证booleantrue
size用于控制该表单内组件的尺寸large / default / small
disabled是否禁用该表单内的所有组件。 如果设置为 true, 它将覆盖内部组件的 disabled 属性booleanfalse
scroll-to-error当校验失败时,滚动到第一个错误表单项booleanfalse
scroll-into-view-options当校验有失败结果时,滚动到第一个失败的表单项目object / boolean

z-filter-form方法

名称说明类型
validate对整个表单的内容进行验证。 接收一个回调函数,或返回 PromiseFunction
validateField验证具体的某个字段。Function
resetFields重置该表单项,将其值重置为初始值,并移除校验结果Function
scrollToField滚动到指定的字段Function
clearValidate清理某个字段的表单验证信息。Function

column属性

属性名说明类型默认值
component表单项组件string / () => VNode
field字段名string
fieldPropscomponent组件属性object
formItemPropsformItem组件属性object
label表单标签名string / () => VNode
hide显隐boolean / (formData) => boolean
show使用v-show显隐boolean / (formData) => boolean
slot表单项自定义内容插槽string
render表单项自定义内容render() => VNode
required表单项是否必填boolean
rules该表单项校验规则boolean
error错误信息string / () => VNode
tooltip提示信息string / () => VNode
extra额外信息string / () => VNode
children表单折叠模式下生效,column数组array
span占据的单元格number
offset左侧的间隔格数number
pull向左移动格数number
push向右移动格数boolean
xs<768px 响应式栅格数或者栅格属性对象number / object
sm≥768px 响应式栅格数或者栅格属性对象number / object
md≥992px 响应式栅格数或者栅格属性对象number / object
lg≥1200px 响应式栅格数或者栅格属性对象number / object
xl≥1920px 响应式栅格数或者栅格属性对象number / object

formItemProps属性

属性名说明类型Default
tooltip提示文案string / () => VNode
extra额外信息string / () => VNode
colon冒号boolean
label标签文本string / () => VNode
label-width标签宽度,例如 '50px'。 可以使用 autostring / number''
required是否为必填项,如不设置,则会根据校验规则确认boolean
rules表单验证规则, 具体配置见下表, 更多内容可以参考async-validatorobject
error表单域验证错误时的提示信息。设置该值会导致表单验证状态变为 error,并显示该错误信息。string / () => VNode
show-message是否显示校验错误信息booleantrue
inline-message是否在行内显示校验信息string / boolean''
size用于控制该表单域下组件的默认尺寸large / default / small
for和原生标签相同能力string
validate-statusformItem 校验的状态error / validating / success

Released under the MIT License.