Appearance
搜索组件
基于 Vue 3 + Element Plus 的配置化搜索表单,用于列表页筛选条件。可与 ProTable 配合使用(通过 search-config),也可独立使用 ProSearchForm。
字段配置与表单字段一致,完整属性见 字段配置。
基本用法
js
const searchConfig = {
labelWidth: '70px',
span: 8,
gutter: 16,
collapse: true,
collapsedRows: 1,
model: { name: '', status: '', type: '', subType: '', date: '' },
fields: [
{ label: '姓名', key: 'name', component: 'input' },
{ label: '状态', key: 'status', component: 'select',
options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }] },
{ label: '类型', key: 'type', component: 'select',
options: [{ label: '类型A', value: 'A' }, { label: '类型B', value: 'B' }] },
{ label: '子类型', key: 'subType', component: 'select',
disabled: (d) => !d.type,
options: (d) => d.type === 'A'
? [{ label: 'A1', value: 'A1' }, { label: 'A2', value: 'A2' }]
: [{ label: 'B1', value: 'B1' }, { label: 'B2', value: 'B2' }] },
{ label: '日期', key: 'date', component: 'date-picker' }
]
}在 ProTable 中使用
vue
<template>
<pro-table
:search-config="searchConfig"
:table-config="tableConfig"
/>
</template>
<script setup>
import { reactive } from 'vue'
const searchConfig = reactive({
model: { name: '', status: '' },
fields: [
{ label: '姓名', key: 'name', component: 'input', placeholder: '请输入姓名' },
{ label: '状态', key: 'status', component: 'select',
options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }] }
]
})
</script>独立使用
vue
<template>
<ProSearchForm
:config="searchConfig"
v-model="searchModel"
@search="onSearch"
@reset="onReset"
/>
</template>
<script setup>
import { ref } from 'vue'
import { ProSearchForm } from 'admin-pro-table'
const searchConfig = {
model: { name: '', status: '' },
fields: [
{ label: '姓名', key: 'name', component: 'input' },
{ label: '状态', key: 'status', component: 'select', options: [...] }
]
}
const searchModel = ref({ ...searchConfig.model })
function onSearch() {
console.log('搜索', searchModel.value)
}
function onReset() {
console.log('重置')
}
</script>Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| config | 搜索配置对象,见下方 Config | Object | 必填 |
| modelValue | 搜索条件数据(支持 v-model) | Object | 必填 |
Config 配置
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| model | 搜索项初始值(进入页面时回显;点击重置会清空,不会恢复为 model) | Object | - |
| labelWidth | 表单项 label 宽度;adaptive 下未配置时为 auto | String | '100px' / auto |
| fields | 搜索项配置数组,结构同 字段配置 | Array | [] |
| span | 每项栅格占位(0–24),可在 field 上单独覆盖;默认 8(一行三个);adaptive 开启后无效 | Number | 8 |
| adaptive | 宽度自适应:不走 span 栅格,表单项按内容宽度横向排列并自动换行 | Boolean | false |
| itemWidth | adaptive 下未配置 field.width 时的控件默认宽度 | String | '180px' |
| itemsPerRow | adaptive + collapse 时估算每行字段数(用于折叠行计算) | Number | 3 |
| bordered | 是否显示搜索区域外边框 | Boolean | false |
| gutter | 栅格间距;adaptive 下作为表单项水平间距 | Number | 20 |
| collapse | 是否启用折叠 | Boolean | false |
| collapsedRows | 折叠时显示的行数 | Number | 1 |
| defaultCollapsed | 默认是否收起 | Boolean | false |
| enterSearch | 是否开启回车触发搜索 | Boolean | true |
| actionsConfig | 搜索操作区配置,见 actionsConfig | Object | - |
自适应宽度与边框
参考紧凑横向筛选栏时,可开启 adaptive + bordered:
js
const searchConfig = reactive({
adaptive: true, // 不按 span 占位,宽度随内容自适应
bordered: true, // 搜索区域外边框
itemWidth: '180px',
gutter: 20,
actionsConfig: { resetText: '清空' },
model: { content: '', operator: '', date: '', object: '' },
fields: [
{ label: '操作内容', key: 'content', component: 'input', placeholder: '支持模糊查询' },
{ label: '操作人', key: 'operator', component: 'input', placeholder: '支持模糊查询' },
{ label: '操作日期', key: 'date', component: 'date-picker', placeholder: '请选择' },
{ label: '对象', key: 'object', component: 'select',
options: [{ label: '全部', value: '' }] }
]
})adaptive: true:使用 flex 换行布局,忽略span;单个字段仍可用field.width覆盖默认itemWidthbordered: true:为搜索区域增加浅色外边框- 折叠仍可用:按
itemsPerRow(默认 3)估算行数,配合collapsedRows
路由带入筛选条件
从其他页跳转并带入手机号等条件时,写在 model 即可回显;点「重置」会清空,不会再写回 model:
js
const searchConfig = reactive({
model: { phone: route.query.phone || '' },
fields: [
{ label: '手机号', key: 'phone', component: 'input' }
]
})actionsConfig
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| show | 是否显示整个操作区 | Boolean | true |
| showSearch | 是否显示搜索按钮 | Boolean | true |
| searchText | 搜索按钮文字 | String | '搜索' |
| showReset | 是否显示重置按钮 | Boolean | true |
| resetText | 重置按钮文字 | String | '重置' |
折叠说明
- 启用
collapse: true后,根据每个字段的span在 24 栅格下计算行数 - 总行数大于
collapsedRows时,右侧显示「展开」「收起」按钮 - 收起时只渲染前
collapsedRows行的字段 - 可通过
defaultCollapsed控制初始是展开还是收起
折叠配置示例
js
const searchConfig = reactive({
model: { name: '', status: '', type: '', subType: '', date: '', region: '' },
span: 8, // 一行三个(24 / 8 = 3)
collapse: true, // 启用折叠
collapsedRows: 1, // 收起时只显示第一行
defaultCollapsed: true, // 默认收起
fields: [
{ label: '姓名', key: 'name', component: 'input' },
{ label: '状态', key: 'status', component: 'select',
options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }] },
{ label: '类型', key: 'type', component: 'select',
options: [{ label: '类型A', value: 'A' }, { label: '类型B', value: 'B' }] },
// 以下字段在收起时隐藏
{ label: '子类型', key: 'subType', component: 'select',
options: [{ label: 'S1', value: 'S1' }, { label: 'S2', value: 'S2' }] },
{ label: '日期', key: 'date', component: 'date-picker' },
{ label: '地区', key: 'region', component: 'input' }
]
})上面的配置效果:
span: 8→ 一行放 3 个字段- 6 个字段 → 2 行
collapsedRows: 1→ 收起时只显示第 1 行(前 3 个字段)defaultCollapsed: true→ 页面打开时默认收起- 右侧自动出现「展开 ↓」按钮,点击后显示全部 6 个字段
不同 span 下的折叠行为
| span | 一行字段数 | 6 个字段共几行 | collapsedRows=1 时显示 |
|---|---|---|---|
| 6 | 4 个 | 2 行 | 前 4 个 |
| 8 | 3 个 | 2 行 | 前 3 个 |
| 12 | 2 个 | 3 行 | 前 2 个 |
| 24 | 1 个 | 6 行 | 前 1 个 |
单个字段可通过
field.span覆盖全局span,折叠计算会按实际栅格累加。
完整折叠 demo
vue
<template>
<ProSearchForm
:config="searchConfig"
v-model="searchModel"
@search="onSearch"
@reset="onReset"
/>
</template>
<script setup>
import { ref, reactive } from 'vue'
const searchConfig = reactive({
labelWidth: '70px',
span: 8,
gutter: 16,
collapse: true,
collapsedRows: 1,
defaultCollapsed: false,
model: { name: '', status: '', type: '', subType: '', date: '' },
fields: [
{ label: '姓名', key: 'name', component: 'input', placeholder: '请输入姓名' },
{ label: '状态', key: 'status', component: 'select',
options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }] },
{ label: '类型', key: 'type', component: 'select',
options: [{ label: '类型A', value: 'A' }, { label: '类型B', value: 'B' }] },
{ label: '子类型', key: 'subType', component: 'select',
disabled: (d) => !d.type,
options: (d) => d.type === 'A'
? [{ label: 'A1', value: 'A1' }, { label: 'A2', value: 'A2' }]
: [{ label: 'B1', value: 'B1' }, { label: 'B2', value: 'B2' }] },
{ label: '日期', key: 'date', component: 'date-picker', placeholder: '选择日期' }
]
})
const searchModel = ref({ ...searchConfig.model })
function onSearch() { console.log('搜索', searchModel.value) }
function onReset() { console.log('重置') }
</script>Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| update:modelValue | 搜索条件变更时触发(v-model) | (model: Object) |
| search | 点击「搜索」时触发 | - |
| reset | 点击「重置」时触发 | - |
Slots
| 插槽名 | 说明 | 作用域参数 |
|---|---|---|
| [field.slot] | 某字段配置 slot: 'xxx' 时的自定义控件 | |
| extra-[key] | 字段下方扩展内容(字段 extra: 'slot') | |
| prepend-[key] | 控件前插槽(字段 prepend: 'slot') | 同上 |
| append-[key] | 控件后插槽(字段 append: 'slot') | 同上 |
prepend / append 也可直接配置为函数,根据当前搜索条件动态显示辅助内容:
js
fields: [
{
label: '金额',
key: 'amount',
component: 'input-number',
prepend: (formData) => formData.currency === 'USD' ? '$' : '¥',
append: (formData) => formData.currency === 'USD' ? '美元' : '人民币'
}
]在 ProTable 中使用时,搜索插槽从 ProTable 透传到 ProSearchForm。建议在字段相关插槽中使用 search- 前缀:
js
fields: [
{ label: '姓名', key: 'name', component: 'input', slot: 'search-custom-name' }
]vue
<pro-table :search-config="searchConfig">
<template #search-custom-name="{ modelValue, field, formData }">
<el-input v-model="formData.name" placeholder="自定义" />
</template>
<template #search-append-amount="{ formData }">
{{ formData.currency === 'USD' ? '美元' : '人民币' }}
</template>
</pro-table>更多插槽说明见 插槽总览。
全局配置
在安装时通过 app.use(AdminProTable, { searchConfig: {...} }) 统一配置搜索表单默认值,单表 searchConfig 可覆盖:
js
app.use(AdminProTable, {
searchConfig: {
labelWidth: '80px',
span: 8,
gutter: 16,
actionsConfig: {
show: true,
showSearch: true,
showReset: true,
searchText: '搜索',
resetText: '重置'
}
}
})字段能力
搜索表单字段支持与表单字段相同的联动能力(visible、disabled、options 函数、watchDeps / onWatchDeps 等),完整说明见 字段配置。
示例:选择类型后才显示子类型搜索项
js
fields: [
{ label: '类型', key: 'type', component: 'select',
options: [{ label: 'A', value: 'A' }, { label: 'B', value: 'B' }] },
{
label: '子类型', key: 'subType', component: 'select',
visible: (formData) => !!formData.type,
options: (formData) => formData.type === 'A'
? [{ label: 'A1', value: 'A1' }]
: [{ label: 'B1', value: 'B1' }]
}
]