Touko
8 months ago|views:52
自定义element-plus搜索框
组件 SearchInput:
<script setup>
import { ref, reactive, watch, onMounted, nextTick } from 'vue';
import { Filter } from '@element-plus/icons-vue';
import { defaultTime, defaultValue, disabledDate } from '@/utlis';
const props = defineProps({
query: Array,
shadow: {
default: 'always',
type: String,
},
});
const emit = defineEmits(['setData', 'resetData']);
const initialize = ref(false);
// 选择的查询类型
const searchType = ref([]);
// 存储所有类型键值
const values = reactive({});
// 加载动画控制
const loading = ref(false);
// 远程加载数据选项
const options = ref([]);
watch(values, v => {
if (initialize.value) {
const queryInfo = {};
getSearchInfo(searchType.value).forEach((item) => {
if (item.type === 'time') {
queryInfo['startTime'] = values[item.value]?.[0] || '';
queryInfo['endTime'] = values[item.value]?.[1] || '';
} else {
queryInfo[item.value] = values[item.value];
}
});
emit('setData', queryInfo);
}
});
onMounted(async () => {
for (const item of props.query) {
values[item.value] = '';
}
await nextTick();
initialize.value = true;
});
/**
* 获取查询信息
* @param {Array} types 选择的查询类型
* @returns {*} 返回已选择的 query 数据
*/
const getSearchInfo = (types) => {
return types.map(type => props.query.find(i => i.value === type)).filter(Boolean);
};
/**
* 聚焦时发起网络请求,更新 select 选择数据
* @param queryInfo 当前聚焦的 query 数据
*/
const handleFocus = async (queryInfo) => {
options.value = [];
try {
loading.value = true;
const { data } = await queryInfo.searchFunction();
Object.entries(data).forEach(([key, value]) => {
options.value.push({ label: value, value: key });
});
loading.value = false;
} catch (e) {
loading.value = false;
console.log(e);
}
};
/**
* 删除单个 tag
* @param tagValue
*/
const handleRemoveTag = (tagValue) => {
values[tagValue] = '';
};
/**
* 清空 tag
*/
const handleClear = () => {
Object.keys(values).forEach((item) => {
values[item] = '';
});
emit('resetData');
};
</script>
<template>
<el-card class="mb-4" :shadow="props.shadow">
<div class="flex justify-between items-center">
<div class="flex items-center">
<el-icon :size="32" class="font-bold">
<Filter />
</el-icon>
<span class="text-2xl ml-4">Filter</span>
</div>
<Transition name="list">
<div v-if="searchType.length === 1" class="w-1/3">
<TransitionGroup name="list">
<template v-for="i in getSearchInfo(searchType)" :key="i.value">
<div>
<el-input clearable v-model="values[i.value]"
:placeholder="`请输入${i.label}`"
v-if="i.type==='input'" />
<el-date-picker
style="width: auto"
v-if="i.type==='time'"
v-model="values[i.value]"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD HH:mm:ss"
:disabled-date="disabledDate"
:default-time="defaultTime"
:default-value="defaultValue()"
/>
<el-radio-group v-if="i.type==='radio'" v-model="values[i.value]">
<el-radio v-for="(label,value) in i.state"
:label="label.text" :value="value"
:key="value"></el-radio>
</el-radio-group>
<el-select
v-if="i.type==='select'" v-model="values[i.value]"
filterable
:loading="loading"
@focus="handleFocus(i)"
:placeholder="`请输入${i.label}`"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<template #loading>
<svg class="circular" viewBox="0 0 50 50">
<circle class="path" cx="25" cy="25" r="20" fill="none" />
</svg>
</template>
</el-select>
</div>
</template>
</TransitionGroup>
</div>
</Transition>
<div class="min-w-32">
<el-select v-model="searchType" placeholder="查询条件" clearable multiple @remove-tag="handleRemoveTag"
@clear="handleClear">
<el-option v-for="i in props.query" :key="i.value" :label="i.label" :value="i.value" />
</el-select>
</div>
</div>
<Transition name="list">
<div class="mt-4 grid grid-cols-1 sm:grid-cols-2 gap-4" v-if="searchType.length>1">
<TransitionGroup name="list">
<template v-for="i in getSearchInfo(searchType)" :key="i.value">
<div>
<el-input clearable v-model="values[i.value]"
:placeholder="`请输入${i.label}`"
v-if="i.type==='input'" />
<el-date-picker
style="width: auto"
v-if="i.type==='time'"
v-model="values[i.value]"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD HH:mm:ss"
:disabled-date="disabledDate"
:default-time="defaultTime"
:default-value="defaultValue()"
/>
<el-radio-group v-if="i.type==='radio'" v-model="values[i.value]">
<el-radio v-for="(label,value) in i.state"
:label="label.text" :value="value"
:key="value"></el-radio>
</el-radio-group>
<el-select
v-if="i.type==='select'" v-model="values[i.value]"
filterable
:loading="loading"
@focus="handleFocus(i)"
:placeholder="`请输入${i.label}`"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<template #loading>
<svg class="circular" viewBox="0 0 50 50">
<circle class="path" cx="25" cy="25" r="20" fill="none" />
</svg>
</template>
</el-select>
</div>
</template>
</TransitionGroup>
</div>
</Transition>
</el-card>
</template>
<style scoped lang="scss">
.list-move,
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateY(30px);
}
.list-leave-active {
position: absolute;
}
.circular {
display: inline;
height: 30px;
width: 30px;
animation: loading-rotate 2s linear infinite;
}
.path {
animation: loading-dash 1.5s ease-in-out infinite;
stroke-dasharray: 90, 150;
stroke-dashoffset: 0;
stroke-width: 2;
stroke: var(--el-color-primary);
stroke-linecap: round;
}
</style>
utils:
时间范围查询默认配置
// el-date-picker 默认配置
export const defaultTime = [new Date(), new Date()];
export const disabledDate = (time) => {
const now = new Date();
return time.getTime() > now.getTime();
};
export const defaultValue = () => {
const now = new Date();
const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1);
const startOfCurrentMonth = new Date(now.getFullYear(), now.getMonth());
return [lastMonth, startOfCurrentMonth];
};
使用:
<search-input :query="foaQuery" shadow="never" @resetData="updateTableData(page)" @setData="setData" />
// 查询条件
export const foaQuery = [
{
label: '用户邮箱',
value: 'email',
type: 'input',
},
{
label:'反馈标题',
value: 'title',
type: 'input',
},
{
label: '时间范围',
value: 'time',
type: 'time',
},
];
// 查询方法
/**
* 更新表格数据
* @param page
* @returns {Promise<void>}
*/
const updateTableData = async (page) => {
const params = {
pageModel: page,
...query.value,
};
if (replyState.value !== 2) {
params.replyState = replyState.value;
}
try {
const res = await getList(params);
if (res?.code === 200) {
const { data: { records, total } } = res;
page.total = total;
tableData.value = records;
}
} catch (e) {
ElMessage.error(e);
}
};
const setData = async (queryInfo) => {
query.value = queryInfo;
await updateTableData(page);
};tags:
0
comments:
It's deserted here, it looks like no one's been here