vue项目收缩搜索表单
需求背景
如果列表的查询字段很多,整个页面全部显示的搜索条件,无疑体验很不好。一般默认只显示几个查询条件,通过点击按钮再显示全部查询条件。
收起状态:显示固定的几个筛选条件(默认筛选条件可自定义),按钮文案——展开。点击按钮切换到“展开状态”;
展开状态:显示全部筛选条件,按钮文案——收缩。点击按钮切换到“收起状态”。
技术栈
vue项目使用element-ui框架
代码实现
html部分
<!-- 收缩搜索表单组件 -->
<template>
<div class="index-search-wrap">
<el-form :model="value"
ref="formInline"
label-width="100px"
label-position="right"
class="form-inline-resevation"
@submit.native.prevent>
<el-row :gutter="32">
<el-col v-for="(item, index) in showConfig"
:key="index"
:span="span">
<el-form-item v-if="!item.hidden"
:prop="item.key"
:label="item.label || item.key">
<template v-if="item.type==='select'">
<DicElSelect v-if="item.dic"
v-model="value[item.key]"
:type="item.key" />
<el-select v-else
v-model="value[item.key]"
:placeholder="item.placeholder || '请选择'">
<el-option v-for="(item, index) in options[item.optKey]"
:key="index"
:label="item.lable"
:value="item.code" />
</el-select>
</template>
<template v-else-if="item.type==='picker'">
<el-date-picker v-model="value[item.key]"
:type="item.pickerType"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期" />
</template>
<template v-else-if="item.type==='cascader'">
<el-cascader ref="cascaderRef"
:options="optionsNew[item.optKey]"
:props="item.cascaderProps||{expandTrigger:'hover'}"
:show-all-levels="item.showAllLevels"
:style="{width:'100%'}"
:placeholder="item.placeholder || '请选择'"
popper-class="cascader-pop"
collapse-tags
clearable
@change="onCascaderChange($event, item.key,item.optKey)">
<template slot-scope="{ node, data }">
<span class="select-item"
@click="handleCascaderSelect">{{data.label}}</span>
</template>
</el-cascader>
</template>
<template v-else>
<el-input v-model.trim="value[item.key]"
:placeholder="item.placeholder|| '请输入'" />
</template>
</el-form-item>
</el-col>
<el-col :span="span"
:offset="operationOffset"
class="button-col">
<slot />
</el-col>
</el-row>
</el-form>
</div>
</template>
组件支持select、datePicker日期选择器、cascader级联选择器、input输入
逻辑部分
<script>
import DicElSelect from '@/components/DicElSelect';
import { fetchDicList } from '@/api/api';
import { cloneDeep, sortBy } from 'lodash';
export default {
name: 'CollapseSearchForm',
components: { DicElSelect },
props: {
config: {
type: Array,
default: () => [],
},
options: {
type: Object,
default: () => ({}),
},
value: {
type: Object,
default: () => ({}),
},
span: {
type: Number,
default: 8,
},
isCollapse: Boolean,
/**
* default show files by order
* eg: [key1, key2]
*/
defaultShow: {
type: Array,
default: () => [],
},
// 一行展示files的数量
rowNum: {
type: [Number, String],
default: 3,
},
},
data() {
return {
optionsNew: {},
};
},
computed: {
defaultNum() {
let len = this.defaultShow.length || 0;
len < 3 && (len = 3);
return len;
},
showConfig({ config, defaultShow = [], defaultNum, isCollapse }) {
const hasdefaultShow = !!defaultShow.length;
let show = [];
if (hasdefaultShow) {
show = defaultShow
.reduce((pre, item) => {
pre.push(config.find((x) => item === x.key));
return pre;
}, [])
.slice(0, defaultNum);
} else {
show = config.slice(0, defaultNum);
}
return isCollapse ? show : config;
},
operationOffset() {
const rowNum = this.rowNum;
const showNum = this.showConfig.length;
let space = showNum % rowNum;
let offset = (rowNum - space - 1) * this.span;
return offset;
},
},
watch: {
options: {
immediate: true,
deep: true,
handler(val) {
this.optionsNew = val;
},
},
},
mounted() {},
methods: {
/**
* @param {Array} val 选中项的Item
* @param {String} key file key
* @param {Boolean} cut last-取最后一级的值;all-取所有级的值
*/
onCascaderChange(val, key, optKey) {
let option = cloneDeep(this.options[optKey]);
let formData = cloneDeep(this.value);
if (val.length) {
const selectedOnLevel = val[0][0];
option.forEach((h) => {
if (h.value !== selectedOnLevel) h.disabled = true;
});
} else {
option.forEach((h) => {
h.disabled = false;
});
}
this.optionsNew[optKey] = option;
let tmp = [];
if (val && Array.isArray(val) && val.length)
tmp = val.map((x) => (x.length === 3 ? x[2] : x.slice(-1)[0]));
formData[key] = tmp;
this.$emit('input', formData);
},
handleCascaderSelect(e) {
let parentPreviousElement = e.target.parentElement.previousElementSibling;
let inputRadio = parentPreviousElement.children[0].children[1];
inputRadio.click();
},
clearSupervisionDepartment() {
const cascaders = this.$refs.cascaderRef || [];
cascaders.forEach((x) => {
x.handleClear();
});
},
},
beforeDestroy() {},
};
</script>
从浏览器方面来讲,这种实现方式还是有待完善的。因为每次切换收起/展开状态,都会引发页面的重排。
样式部分
显示样式代码
<style lang="scss" scoped>
@import '~scss_vars';
.index-search-wrap {
margin-bottom: 16px;
@include backandPadding(0);
.button-col {
text-align: right;
padding-bottom: 16px;
}
}
</style>
<style lang="scss">
.cascader-pop {
.el-cascader-menu__wrap {
height: 310px;
}
.el-scrollbar__bar.is-vertical {
opacity: 1;
width: 8px;
}
}
</style>
结言:如果有好的思路,欢迎指出😀

浙公网安备 33010602011771号