Search

封装搜索组件实现通过配置动态生成表单

提示

Search 组件基于 Form 组件实现。

最主要的区别是 Search 组件会为 columns 属性的每一个值增加默认布局参数 { xs: 24, md: 12, lg: 8, xl: 6 }

另外 [prop] 相关的插槽也由 form-[prop] 更改为 search-[prop]

使用

基础用法

<template>
  <pro-search
    v-model="search"
    :columns="columns"
    label-width="100px"
    @submit="submit"
  />
</template>

<script>
import { defineComponent, ref } from 'vue'
import { ElMessage } from 'element-plus'

export default defineComponent({
  setup() {
    const search = ref({})
    const columns = [
      {
        label: 'Name',
        prop: 'name',
        component: 'el-input',
      },
      {
        label: 'Address',
        prop: 'address',
        component: 'el-input',
      },
      {
        label: 'Date',
        prop: 'date',
        component: 'el-date-picker',
        props: {
          type: 'date',
          style: 'width: 100%',
        },
      },
    ]
    const submit = (done, isValid, invalidFields) => {
      ElMessage(`submit: ${isValid}`)
      console.log(search.value, isValid, invalidFields)
      setTimeout(() => {
        done()
      }, 1000)
    }

    return {
      search,
      columns,
      submit,
    }
  },
})
</script>

智能提示

通过辅助函数 defineSearchColumns defineSearchMenuColumns defineSearchSubmit 提供智能提示

<template>
  <pro-search
    v-model="search"
    :columns="columns"
    :menu="menu"
    label-width="100px"
    @submit="submit"
  />
</template>

<script>
import { defineComponent, ref } from 'vue'
import { ElMessage } from 'element-plus'
import {
  defineSearchColumns,
  defineSearchMenuColumns,
  defineSearchSubmit,
} from 'element-pro-components'

export default defineComponent({
  setup() {
    const search = ref({})
    const menu = defineSearchMenuColumns({
      submitText: 'Create',
      reset: false,
    })
    const columns = defineSearchColumns([
      {
        label: 'Name',
        prop: 'name',
        component: 'el-input',
      },
      {
        label: 'Address',
        prop: 'address',
        component: 'el-input',
      },
      {
        label: 'Date',
        prop: 'date',
        component: 'el-date-picker',
        props: {
          type: 'date',
          style: 'width: 100%',
        },
      },
    ])
    const submit = defineSearchSubmit((done, isValid, invalidFields) => {
      ElMessage(`submit: ${isValid}`)
      console.log(search.value, isValid, invalidFields)
      setTimeout(() => {
        done()
      }, 1000)
    })

    return {
      menu,
      search,
      columns,
      submit,
    }
  },
})
</script>

使用插槽

直接在模版中增加带 search-[prop] 相关的插槽即可使用。虽然在启用插槽后可以通过 v-model="form.slot" 这种方式绑定值,但更推荐使用 valuesetValue

<template>
  <pro-search
    v-model="search"
    :columns="columns"
    label-width="100px"
    @submit="submit"
  >
    <template #menu-right>
      <el-button>menu-right</el-button>
    </template>
    <template #search-slot-label>
      <span>name</span>
    </template>
    <template #search-slot="{ value, setValue }">
      <el-input :value="value" @change="setValue">
        <template #prefix>
          <el-icon>
            <element-plus />
          </el-icon>
        </template>
      </el-input>
    </template>
  </pro-search>
</template>

<script>
import { defineComponent, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { ElementPlus } from '@element-plus/icons-vue'
import { defineFormColumns, defineFormSubmit } from 'element-pro-components'

export default defineComponent({
  components: { ElementPlus },
  setup() {
    const search = ref({})
    const columns = defineFormColumns([
      {
        prop: 'slot',
      },
    ])
    const submit = defineFormSubmit((done, isValid, invalidFields) => {
      ElMessage(`submit: ${isValid}`)
      console.log(search.value, isValid, invalidFields)
      setTimeout(() => {
        done()
      }, 1000)
    })

    return {
      search,
      columns,
      submit,
    }
  },
})
</script>

TypeScript

defineSearchColumns 支持传入一个泛型用来推断 prop 值;defineComponentProps 支持传入一个泛型用来辅助输入 props

<template>
  <pro-search
    v-model="search"
    :columns="columns"
    label-width="100px"
    @submit="submit"
  />
</template>

<script setup lang="ts">
import { markRaw, ref } from 'vue'
import { ElDatePicker, ElMessage } from 'element-plus'
import {
  defineSearchColumns,
  defineSearchSubmit,
  defineComponentProps,
} from 'element-pro-components'

interface Search {
  name?: string
  date?: string[]
}

const search = ref<Search>({})
const columns = defineSearchColumns<Search>([
  {
    label: 'Name',
    prop: 'name',
    component: 'ElInput',
    props: defineComponentProps<'ElInput'>({
      clearable: true,
      placeholder: 'Please input your name',
      slots: {
        append: () => 'Search',
      },
    }),
  },
  {
    label: 'Date',
    prop: 'date',
    component: markRaw(ElDatePicker),
    props: defineComponentProps<typeof ElDatePicker>({
      type: 'daterange',
      style: 'width: 100%',
    }),
  },
])
const submit = defineSearchSubmit((done, isValid, invalidFields) => {
  ElMessage(`submit: ${isValid}`)
  console.log(search.value, isValid, invalidFields)
  setTimeout(() => {
    done()
  }, 1000)
})
</script>

配置

参数说明类型可选值默认值
v-model绑定值object / array--
columns表单配置参考下面 columnsarray--
menu按钮配置参考下面 menuobject--
config每项的默认布局配置object-{ xs: 24, md: 12, lg: 8, xl: 6 }
rules表单验证规则object--
inline行内表单模式boolean-false
array是否启用数组表单boolean-
max限制数组表单的最大数量number--
label-position表单域标签的位置,如果值为 left 或者 right 时,则需要设置 label-widthstringright / left / topright
label-width表单域标签的宽度,例如 ‘50px’ 或 ‘auto’string--
label-suffix表单域标签的后缀string--
hide-required-asterisk是否显示必填字段的标签旁边的红色星号boolean-false
show-message是否显示校验错误信息boolean-true
inline-message是否以行内形式展示校验信息boolean-false
status-icon是否在输入框中显示校验结果反馈图标boolean-false
validate-on-rule-change是否在 rules 属性改变后立即触发一次验证boolean-true
size用于控制该表单内组件的尺寸stringlarge / default /small-
disabled是否禁用该表单内的所有组件boolean-false
scroll-to-error当校验失败时,滚动到第一个错误表单项boolean-false
scroll-into-view-options当校验有失败结果时,滚动到第一个失败的表单项目 可通过 scrollIntoView 配置object / boolean-
gutter栅格间隔number-0
justifyflex 布局下的水平排列方式stringstart / end / center / space-around / space-between / spacing-evenlystart
alignflex 布局下的垂直排列方式stringtop / middle / bottomtop

columns

参数说明类型可选值默认值
propv-model 绑定的字段名 (需要是唯一值)string--
label标签文本string--
component当前项对应的组件,可以直接传入局部组件string / Component--
props传递的对应的组件的参数object--
models配置当前项对应的组件的 v-model 绑定的参数 (Array<{ prop, key, event }>)array--
children分组表单或子表单内容array--
typechildren 内部表单的类型stringarray / group / tabs / collapse / stepsarray
max限制 type=array 时子表单的最大数量number--
show是否在表单中显示当前项boolean-true
labelWidth表单域标签的宽度,例如 ‘50px’ 或 ‘auto’string--
labelPosition表单域标签的位置, 当设置为 left 或 right 时,则也需要设置 label-width 属性 默认会继承 Form的label-positionstringleft / right / top-
required是否必填,如不设置,则会根据校验规则自动生成boolean-false
rules表单验证规则object / array--
error表单域验证错误信息, 设置该值会使表单验证状态变为error,并显示该错误信息string--
showMessage是否显示校验错误信息boolean-true
inlineMessage以行内形式展示校验信息boolean-false
size用于控制该表单域下组件的尺寸stringlarge / default /small-
span栅格占据的列数number-24
offset栅格左侧的间隔格数number-0
push栅格向右移动格数number-0
pull栅格向左移动格数number-0
xs<768px 响应式栅格数或者栅格属性对象number / object--
sm≥768px 响应式栅格数或者栅格属性对象number / object--
md≥992px 响应式栅格数或者栅格属性对象number / object--
lg≥1200px 响应式栅格数或者栅格属性对象number / object--
xl≥1920px 响应式栅格数或者栅格属性对象number / object--
disabled是否禁用, 当 type=tabs 或者 type=collapse 时生效booleanfalse
closable标签是否可关闭, 当 type=tabs 时生效booleanfalse
lazy标签是否延迟渲染, 当 type=tabs 时生效booleanfalse
description分步描述文案, 当 type=steps 时生效string
icon自定义分步图标, 当 type=steps 时生效string / Component
status设置当前步骤的状态, 当 type=steps 时生效stringwait / process / finish / error / success

关于 props

props 的属性将全部传递给 component 指定的组件

  • 对于存在连字符的属性,可以通过字符串包裹或者转换为驼峰结构
  • 通过 slots 可以向组件传递简单的渲染函数
  • 对于事件需要通过 on[Event] 驼峰这种形式绑定。如:change -> onChange, input -> onInput
props: {
  clearable: true,
  'prefix-icon': 'el-icon-search',
  suffixIcon: 'el-icon-date',
  slots: {
    prefix: () => h('i', { className: 'el-input__icon el-icon-search' }),
    append: () => '搜索'
  },
  onChange: e => console.log(e),
}
参数说明类型默认值
submit是否显示 submit 按钮booleantrue
submitTextsubmit 按钮显示的文字stringSearch
submitPropssubmit 按钮的配置,参考 el-buttonobject{ type: ‘primary’ }
reset是否显示 reset 按钮booleantrue
resetTextreset 按钮显示的文字stringReset
resetPropsreset 按钮的配置,参考 el-buttonobject-
prevTextprev 按钮显示的文字stringPrev
prevPropsprev 按钮的配置,参考 el-buttonobject-
nextTextnext 按钮显示的文字stringNext
nextPropsnext 按钮的配置,参考 el-buttonobject-

事件

事件名说明参数
submitsubmit 被点击后触发(done: () => void, isValid: boolean, invalidFields) => void
resetreset 按钮被点击后触发() => void
validate任一表单项被校验后触发(prop: FormItemProp, isValid: boolean, message: string) => void
add-itemadd 被点击后触发(indexes: number[]) => void
remove-itemremove 被点击后触发(indexes: number[]) => void
collapse-changecollapse 改变时触发(active: CollapseModelValue) => void
tab-changetab 改变时触发(name: TabPaneName) => void
step-changestep 改变时触发(active: string | number) => void

方法

方法名说明参数
validate对整个表单进行校验的方法,参数为一个回调函数。该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则会返回一个 promise(callback?: FormValidateCallback) => void
validateField对部分表单字段进行校验的方法(props?: string | string[], callback?: FormValidateCallback) => FormValidationResult
resetFields对整个表单进行重置,将所有字段值重置为初始值并移除校验结果(props?: string | string[]) => void
scrollToField滚动到指定表单字段(prop: string) => void
clearValidate移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果(props?: string | string[]) => void

插槽

名称说明类型
-在底部菜单前插入的任意内容-
menu-left搜索表单底部按钮左侧{ loading: boolean }
menu-right搜索表单底部按钮右侧{ loading: boolean }
search-[prop]当前这项的 Search Item 的内容{ item: object, indexes?: number[], value: any, setValue: (value: any) => void }
search-[prop]-label当前这项的标签文本的内容{ item: object, indexes?: number[] }
search-[prop]-error当前这项的自定义表单校验信息的显示方式{ error, item: object, indexes?: number[] }

提示

[prop] 为 columns 中定义的 prop