搜索
在列中配置 search: true 即可生成搜索项。搜索只收集条件,列表过滤或接口请求由 search-change 处理。将搜索与分页结合的完整示例见 分页与搜索一起使用。
搜索变量
v-model:search 绑定搜索表单,字段名仍对应列 prop。它记录正在输入的值;真正提交到接口的参数从 search-change 获取。
<template>
{{ search }}
<avue-crud :option="option"
v-model:search="search"
:data="data">
</avue-crud>
</template>
<script setup>
import { ref } from 'vue';
const search = ref({ name: 'small' });
const data = ref([{ name: '张三' }]);
const option = ref({
column: [
{
label: '姓名',
prop: 'name',
search: true
}
]
});
</script>
搜索按钮文字和图标配置
searchBtnText/emptyBtnText 设置搜索、清空文字,searchBtnIcon/emptyBtnIcon 设置对应图标;searchBtn、emptyBtn 可以单独关闭按钮。
<template>
<avue-crud :option="option"
:data="data" />
</template>
<script setup>
import { ref } from 'vue';
const data = ref([{ name: '张三' }]);
const option = ref({
searchBtnText: '查询',
searchBtnIcon: 'el-icon-user',
emptyBtnText: '重置',
emptyBtnIcon: 'el-icon-close',
column: [
{
label: '姓名',
prop: 'name',
search: true,
}
]
});
</script>
搜索方法
点击搜索触发 search-change(params, done),请求结束后调用 done 关闭提交状态;点击清空触发 search-reset(searchForm),需要业务自行恢复列表。
<template>
<avue-crud :option="option"
:data="data"
@search-change="searchChange"
@search-reset="resetChange">
</avue-crud>
</template>
<script setup>
import { ref } from 'vue';
import { ElMessage } from 'element-plus';
const data = ref([{ name: '张三' }]);
const option = ref({
column: [
{
label: '姓名',
prop: 'name',
search: true,
}
]
});
function resetChange (item) {
ElMessage.success('清空回调');
}
function searchChange (params, done) {
ElMessage.success('2s后关闭锁定');
setTimeout(() => {
done();
ElMessage.success(JSON.stringify(params));
}, 2000);
}
</script>
提交前会去掉空值和包含 $ 的字段,数字 0、false 不会当作空值。配置 searchProp: 'keyword' 可把某列提交时的字段名改为 keyword;原始搜索模型仍保留该列 prop。
搜索字段标题宽度
searchLabelWidth 默认 80,可以配置在 option 上作用于全部搜索项,也可在列中覆盖。
<template>
<avue-crud :data="data"
:option="option"></avue-crud>
</template>
<script setup>
import { ref } from 'vue';
const data = ref([
{ name: '张三', sex: '男' },
{ name: '李四', sex: '女' }
]);
const option = ref({
searchLabelWidth: 150,
column: [
{
label: '姓名',
prop: 'name',
searchLabelWidth: 30,
search: true
},
{
label: '性别',
prop: 'sex',
search: true
}
]
});
</script>
搜索字段排序
searchOrder 默认 0,数值越大越靠前,只改变搜索字段顺序,不改变表格列顺序。
<template>
<avue-crud :data="data"
:option="option"></avue-crud>
</template>
<script setup>
import { ref } from 'vue';
const data = ref([
{ name: '张三', sex: '男' },
{ name: '李四', sex: '女' }
]);
const option = ref({
column: [
{
label: '姓名',
prop: 'name',
search: true
},
{
label: '性别',
prop: 'sex',
search: true,
searchOrder: 1
}
]
});
</script>
搜索过滤
比较正在输入的 search 对象与实际提交参数。输入姓名并选择状态,点击搜索后查看 searchProp 改名、空值清理以及数字 0 的保留。
<template>
<div>
<avue-crud v-model:search="search"
:data="data"
:option="option"
@search-change="searchChange"
@search-reset="searchReset" />
<div class="search-preview" aria-live="polite">
<div><strong>正在输入的 search</strong><pre>{{ search }}</pre></div>
<div><strong>最近提交的 params</strong><pre>{{ submitted }}</pre></div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const search = ref({});
const submitted = ref({});
const data = ref([{ id: 1, name: '张三', status: 0 }]);
const option = ref({
rowKey: 'id',
addBtn: false,
menu: false,
refreshBtn: false,
columnBtn: false,
gridBtn: false,
searchSpan: 12,
searchMenuSpan: 24,
column: [
{ label: '姓名', prop: 'name', search: true, searchProp: 'keyword' },
{
label: '状态',
prop: 'status',
type: 'select',
search: true,
dicData: [{ label: '待处理', value: 0 }, { label: '已完成', value: 1 }]
}
]
});
function searchChange(params, done) {
submitted.value = params;
done();
}
function searchReset() {
submitted.value = {};
}
</script>
<style scoped>
.search-preview { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-top: 16px; }
.search-preview > div { padding: 14px; border-radius: 8px; background: var(--el-fill-color-light); }
.search-preview pre { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 13px; }
@media (max-width: 640px) { .search-preview { grid-template-columns: 1fr; } }
</style>
搜索验证规则
searchRules 为搜索表单设置独立规则;不会自动沿用编辑表单的 rules。校验不通过时不会提交搜索。
<template>
<avue-crud :option="option"
:data="data">
</avue-crud>
</template>
<script setup>
import { ref } from 'vue';
const data = ref([{ name: '张三' }]);
const option = ref({
column: [
{
label: '姓名',
prop: 'name',
search: true,
searchRules: [
{
required: true,
message: "请输入姓名",
trigger: "blur"
}
]
},
{
label: '日期',
prop: 'date',
type: 'datetime'
}
]
});
</script>
搜索范围和宽度
searchSpan 默认 6,按 24 栅格控制宽度;searchRange 将支持的输入类型切换为范围输入,范围值是数组。
<template>
<avue-crud :option="option"
:data="data" />
</template>
<script setup>
import { ref } from 'vue';
const data = ref([{ name: '张三', date: '' }]);
const option = ref({
column: [
{
label: '姓名',
prop: 'name',
search: true,
},
{
label: '日期',
prop: 'date',
type: 'datetime',
search: true,
searchSpan: 18,
searchRange: true,
}
]
});
</script>
搜索默认值
searchValue 是搜索项初始值,与新增表单的 value 相互独立。需要初始化时就请求默认条件,应在首次加载逻辑中明确使用这些条件。
<template>
<avue-crud :option="option"
:data="data"></avue-crud>
</template>
<script setup>
import { ref } from 'vue';
const data = ref([
{ name: '张三' }
]);
const option = ref({
column: [
{
label: '姓名',
prop: 'name',
searchValue: 'small',
search: true
}
]
});
</script>
局部展开收缩
searchIcon: true 开启半折叠,超过 searchIndex(默认 2)个搜索项时显示展开按钮;可通过 search-icon-change 获取展开状态。
<template>
<avue-crud :option="option"
:data="data"></avue-crud>
</template>
<script setup>
import { ref } from 'vue';
const data = ref([
{ text1: '文本1', text2: '文本2' }
]);
const option = ref({
searchIndex: 3,
searchIcon: true,
column: [
{
label: '内容1',
prop: 'text1',
search: true
},
{
label: '内容2',
prop: 'text2',
search: true
},
{
label: '内容3',
prop: 'text3',
search: true
},
{
label: '内容4',
prop: 'text4',
search: true
}
]
});
</script>
辅助提示语
searchTip 配置提示内容,searchTipPlacement 配置方向,沿用对应表单字段的提示能力。
<template>
<avue-crud :option="option"
:data="data" />
</template>
<script setup>
import { ref } from 'vue';
const data = ref([
{ text1: '文本1', text2: '文本2' }
]);
const option = ref({
column: [
{
label: '内容1',
prop: 'text1',
search: true,
searchTip: '我是一个默认提示语',
},
{
label: '内容2',
prop: 'text2',
search: true,
searchTip: '我是一个左边提示语',
searchTipPlacement: 'left',
}
]
});
</script>
隐藏搜索折叠按钮
searchShowBtn: false 关闭工具栏中的搜索显隐按钮;searchShow: false 则控制搜索区初始收起。
<template>
<avue-crud :option="option"
:data="data" />
</template>
<script setup>
import { ref } from 'vue';
const data = ref([{ name: '张三' }]);
const option = ref({
searchShowBtn: false,
column: [
{
label: '姓名',
prop: 'name',
search: true,
},
{
label: '日期',
prop: 'date',
type: 'datetime',
search: true,
}
]
});
</script>
按钮是否单独成行
searchMenuSpan 控制搜索按钮区所占栅格,结合 searchSpan 调整同一行能容纳的字段数量。
<template>
<avue-crud :option="option"
:data="data"></avue-crud>
</template>
<script setup>
import { ref } from 'vue';
const data = ref([
{ text1: '文本1', text2: '文本2' }
]);
const option = ref({
searchMenuSpan: 8,
column: [
{
label: '内容1',
prop: 'text1',
search: true
},
{
label: '内容2',
prop: 'text2',
search: true
}
]
});
</script>
定义类型
searchType 可以覆盖搜索组件类型,例如表格保存文本而搜索使用下拉选择。
<template>
<avue-crud :option="option"
:data="data" />
</template>
<script setup>
import { ref } from 'vue';
const dic = [
{ label: '选项1', value: 1 },
{ label: '选项2', value: 2 }
];
const data = ref([{
selects: [1, 2],
select: 1
}]);
const option = ref({
column: [
{
label: '多选框',
prop: 'selects',
type: 'select',
multiple: true,
search: true,
searchType: 'checkbox',
searchSpan: 24,
dicData: dic
},
{
label: '单选框',
prop: 'select',
type: 'select',
search: true,
searchType: 'radio',
searchSpan: 24,
dicData: dic
}
]
});
</script>
自定义搜索插槽
search 和 search-menu 自定义搜索内容及按钮。自定义输入仍绑定 v-model:search,不需要为这个输入额外设置列 search。点击「自定义提交」查看传入的参数。
<template>
<div>
<avue-crud :option="option" v-model:search="search" :data="data">
<template #search-menu="{ row, size }">
<el-button :size="size" type="primary" @click="searchSubmit(row)">自定义提交</el-button>
</template>
<template #search="{ size }">
<div class="custom-search">
<label for="custom-search-keyword">姓名</label>
<el-input id="custom-search-keyword"
v-model="search.keyword"
:size="size"
clearable
placeholder="输入姓名关键字"
@keyup.enter="searchSubmit(search)" />
</div>
</template>
</avue-crud>
<p aria-live="polite">最近提交:{{ submitted || '尚未提交' }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
const search = ref({ keyword: '' });
const submitted = ref('');
const data = ref([{ id: 1, name: '张三' }, { id: 2, name: '李四' }]);
const option = ref({
rowKey: 'id',
addBtn: false,
menu: false,
gridBtn: false,
refreshBtn: false,
columnBtn: false,
searchBtn: false,
emptyBtn: false,
column: [{ label: '姓名', prop: 'name' }]
});
function searchSubmit(row) {
submitted.value = JSON.stringify({ keyword: row.keyword || '' });
}
</script>
<style scoped>
.custom-search { display: flex; align-items: center; gap: 12px; padding-bottom: 12px; }
.custom-search label { flex-shrink: 0; }
.custom-search .el-input { width: 260px; max-width: 100%; }
</style>
插槽名是 search-menu,不是 searchMenu。prop-search 的作用范围是一项输入,search 是整个搜索区的追加内容。
自定义列搜索
使用字段 prop 加 -search 作为插槽名称,作用域参数沿用 Form 字段。
<template>
<avue-crud :option="option"
:data="data"
v-model:search="search">
<template #age-search="{ disabled, size }">
<el-slider :disabled="disabled"
:size="size"
v-model:value="search.age" />
</template>
</avue-crud>
</template>
<script setup>
import { ref } from 'vue';
const search = ref({});
const data = ref([{ name: '张三', age: 18 }]);
const option = ref({
column: [
{
label: '姓名',
prop: 'name',
search: true,
},
{
label: '年龄',
prop: 'age',
search: true
}
]
});
</script>
多级联动
父字段的 cascader 指向子字段的 prop,可配置多个子字段。搜索区的级联由搜索表单管理;dicInit('cascader') 用于列表级联标签回显,不用于提交搜索。
<template>
<avue-crud ref="crud"
:option="option"
:data="data"></avue-crud>
</template>
<script setup>
import { ref, onMounted, nextTick } from 'vue';
const baseUrl = 'https://api.avuejs.com/area';
const data = ref([]);
const option = ref({
excelBtn: true,
column: [
{
label: '省份',
prop: 'province',
type: 'select',
props: { label: 'name', value: 'code' },
cascader: ['city'],
search: true,
dicUrl: `${baseUrl}/getProvince`,
rules: [
{ required: true, message: '请选择省份', trigger: 'blur' }
]
},
{
label: '城市',
prop: 'city',
type: 'select',
cascader: ['area'],
props: { label: 'name', value: 'code' },
search: true,
dicUrl: `${baseUrl}/getCity/{{key}}`,
rules: [
{ required: true, message: '请选择城市', trigger: 'blur' }
]
},
{
label: '地区',
prop: 'area',
type: 'select',
props: { label: 'name', value: 'code' },
search: true,
dicUrl: `${baseUrl}/getArea/{{key}}`,
rules: [
{ required: true, message: '请选择地区', trigger: 'blur' }
]
}
]
});
const crud = ref(null);
onMounted(() => {
data.value = [
{ id: 1, name: '张三', province: '110000', city: '110100', area: '110101' },
{ id: 2, name: '李四', province: '140000', city: '140600', area: '140623' }
]
//加载完数据后调用
nextTick(() => {
crud.value.dicInit('cascader');
});
});
</script>
单独日期搜索
dateBtn: true 显示工具栏日期范围输入;通过 date-change(params) 取得变化,选中值在 params.value 中。它与 v-model:search 是独立入口。
<template>
<avue-crud ref="crud"
@date-change="dateChange"
:option="option"
:data="data"></avue-crud>
</template>
<script setup>
import { ref } from 'vue';
import { ElMessage } from 'element-plus';
const data = ref([
{ text1: '内容1-1', text2: '内容1-2' },
{ text1: '内容2-1', text2: '内容2-2' },
{ text1: '内容3-1', text2: '内容3-2' }
]);
const option = ref({
dateBtn: true,
column: [
{ label: '列内容1', prop: 'text1' },
{ label: '列内容2', prop: 'text2' }
]
});
const dateChange = (date) => {
ElMessage.success(JSON.stringify(date));
};
</script>
