做web端页面时,伴随列表的是各种各样的搜索条件,当各种页面搜索条件都比较多时,此组件将简化代码
组件1: 无更多查询按钮,一行显示所有搜索条件
<template>
<div class="searchArea">
<el-form
v-if="fieldColumns.length > 0"
ref="formRef"
:inline="inline"
:model="formData"
class="elForm"
v-bind="formOpt"
>
<template v-for="item in fieldColumns">
<component
:is="'el-form-item'"
v-if="!item.slot"
:label="item.label"
:prop="item.name"
v-bind="item.formItemOpt"
>
<component
:is="`el-${item.type}`"
v-model="formData[item.name]"
:disabled="item.disabled || false"
:placeholder="item.placeholder"
v-bind="item.opt"
@change="handleChange"
>
<template v-if="item.type === 'select'">
<el-option
v-for="val in item.options"
:key="val.value"
:label="val.label"
:value="val.value"
></el-option>
</template>
</component>
</component>
<slot v-else :name="item.slot" class="tool"></slot>
</template>
</el-form>
<div v-if="isDesc" class="desc">
<slot name="desc"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'SearchArea',
props: {
formOpt: {
type: Object,
default: () => {
},
},
fieldColumns: {
type: Array,
default: () => [],
},
// 是否有文本内容
isDesc: {
type: Boolean,
default: false,
},
// 传来的表单数据
formDataProp: {
type: Object,
default: () => {
},
},
inline: {
type: Boolean,
default: true,
},
},
data() {
return {
formData: {},
};
},
mounted() {
if (this.formDataProp) {
this.formData = this.formDataProp;
}
},
methods: {
handleChange(v) {
this.$emit('handleQuery', v,this.formData);
},
// 把表单数据给到父组件
submitFormData() {
return this.formData;
},
},
};
</script>
<style lang="less" scoped>
.searchArea {
padding: 16px 24px 0;
.tool {
width: fit-content;
margin-left: auto;
}
/deep/ .el-form {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
.el-form-item {
display: flex;
align-items: center;
margin: 0 16px 16px 0;
.el-form-item__label {
line-height: 32px;
padding-right: 8px;
font-size: 14px;
font-weight: 400;
color: #333333;
}
.el-form-item__content {
line-height: 32px;
}
.el-input__inner {
width: 240px;
height: 32px;
line-height: 32px;
border-radius: 2px;
padding: 0 16px 0 12px;
}
.el-input__suffix {
display: grid;
place-content: center;
}
}
//.el-form-item:nth-of-type(5) {
// margin-right: 0;
//}
}
/deep/ .el-button {
height: 32px;
padding: 0 20px;
line-height: 32px;
border-radius: 2px;
}
.desc {
margin-bottom: 16px;
}
}
</style>
使用方式:
<template>
<search-area
ref="searchFormRef"
:fieldColumns="fieldColumns"
:formDataProp="formData"
:resetBtn="false"
@handleQuery="handleQuery"
></search-area>
</template>
<script>
export default {
data(){
return {
fieldColumns:[
{
name: 'year',
label: '入学年份',
type: 'select',
options: [],//通过接口获取下拉列表
semesterId: '',
},
{
name: 'collegeId',
label: '所属院系',
type: 'select',
options: [],
},
{
name: 'majorId',
label: '专业方向',
type: 'select',
options: [],
},
],
formData: {
year: '',//筛选条件中的默认值
collegeId: '',
majorId: '',
},
}
}
methods:{
//筛选条件改变
handleQuery(v, formData) {
}
}
}
</script>
组件2:有更多查询按钮,折叠显示所有搜索条件
使用方式 :与上述基本一致,在增加一个disabled属性,表示是否需要将搜索条件进行隐藏,换行中显示
如下:
{ name: 'majorId', label: '方向(专业)', type: 'select', width: '360px', options: [], disabled: false, },
<template>
<div :class="fold ? '' : 'fold-search--expanded'" class="fold-search inline-flex">
<el-form
v-if="fieldColumns.length > 0"
ref="formRef"
:model="formData"
class="fold-search__area inline-flex"
v-bind="formOpt"
>
<div ref="areaRef" :style="{ width: formAreaWidth }" class="area__form flex justify-start items-start flex-wrap">
<template v-for="item in fieldColumns">
<component
:is="'el-form-item'"
v-if="!item.slot"
:class="['form__item', ( fold && item.hide ) ? 'form__item--hide' : '']"
:label="item.label"
:prop="item.name"
v-bind="item.formItemOpt"
>
<component
:is="`el-${item.type}`"
v-model="formData[item.name]"
:disabled="item.disabled || false"
:style="{width:item.width|| '240px'}"
v-bind="item.opt"
@change="onSubmit"
>
<template v-if="item.type === 'select'">
<el-option
v-for="val in item.options"
:key="val.value"
:label="val.label"
:value="val.value"
></el-option>
</template>
</component>
</component>
<div v-else :class="['form__item', ( fold && item.hide ) ? 'form__item--hide' : '', item.class]">
<slot :name="item.slot"/>
</div>
</template>
<div v-if="showReset" :class="['form__item', fold ? 'form__item--hide' : '']">
<el-button class="query-btn" type="primary" @click="handleReset">{{ resetText }}</el-button>
</div>
</div>
<div class="form__toggle select-none cursor-pointer">
<div class="more-search flex justify-center items-center" @click="toggleHide">
<el-divider direction="vertical"/>
<span>{{ moreText }}</span>
<i :class="[fold ? 'more-search__icon--down' : 'more-search__icon--up']"
class="more-search__icon el-icon-d-arrow-left"></i>
</div>
</div>
</el-form>
</div>
</template>
<script>
export default {
name: 'FoldSearchArea',
model: {
prop: 'value',
event: 'update:value',
},
props: {
// 是否折叠。true折叠,false展开
value: {
type: Boolean,
default: true,
},
formOpt: {
type: Object,
default: () => {
},
},
fieldColumns: {
type: Array,
default: () => [],
},
// 是否有文本内容
isDesc: {
type: Boolean,
default: false,
},
// 传来的表单数据
formDataProp: {
type: Object,
default: () => {
},
},
// 是否显示重置按钮
showReset: {
type: Boolean,
default: false,
},
// 重置按钮的文本
resetText: {
type: String,
default: '重置'
},
moreText: {
type: String,
default: '更多查询',
},
},
data() {
return {
fold: this.value,
formData: {},
formAreaWidth: null,
};
},
watch: {
fold() {
this.$emit('update:value', this.fold);
},
},
computed: {
plainFormItemCount() {
let count = 0;
for (let formItem of this.fieldColumns) {
if (!formItem.hide) {
count++;
} else {
break;
}
}
return count;
},
},
created() {
if (this.formDataProp) {
this.formData = this.formDataProp;
}
// 遍历给formData加属性
for (const item of this.fieldColumns) {
// 用响应式set加,否则输入不上值
this.$set(this.formData, item.name, '');
}
},
mounted() {
if (this.plainFormItemCount > 0) {
let totalWidth = 0;
let children = this.$refs.areaRef.getElementsByClassName('form__item');
Array.prototype.forEach.call(children, (el, count) => {
if (!el.classList.contains('form__item--hide') && count < this.plainFormItemCount) {
totalWidth += el.getBoundingClientRect().width + 16;
}
});
// 遍历第一行显示的元素,计算宽度
this.formAreaWidth = `${totalWidth + 1}px`;
}
},
methods: {
onSubmit(v) {
this.$emit('handleQuery', this.formData, v);
},
// 把表单数据给到父组件
submitFormData() {
return this.formData;
},
// 切换隐藏状态
toggleHide() {
this.fold = !this.fold;
},
// 重置
handleReset() {
this.$refs.formRef.resetFields();
this.$emit('reset', {});
console.log(this.formData, 'this.formData')
this.$emit('handleQuery', this.formData);
}
},
};
</script>
<style lang="less" scoped>
@import "@/styles/common/index.less";
/deep/ .el-form {
.el-form-item {
display: flex;
align-items: center;
margin: 0 16px 5px 0;
.el-form-item__label {
line-height: 32px;
padding-right: 8px;
font-size: 14px;
font-weight: 400;
color: #333333;
}
.el-form-item__content {
line-height: 32px;
}
}
.el-input {
width: 100%;
.el-input__inner {
width: 100%;
height: 32px;
line-height: 32px;
border-radius: 2px;
padding: 0 16px 0 12px;
}
}
.el-input__suffix {
display: grid;
place-content: center;
}
}
.fold-search {
padding: 16px 24px 0;
transition-property: height, border;
transition-duration: .2s;
transition-timing-function: ease-in-out;
&.fold-search--expanded {
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.15);
}
}
.form__item {
margin-bottom: 20px !important;
&.form__item--hide {
display: none;
}
}
.form__toggle {
margin-left: -12px;
}
.more-search {
height: 32px;
color: #3070F9;
span {
margin-left: 4px;
}
.more-search__icon {
margin-left: 4px;
transition: all .2s ease-in-out;
&.more-search__icon--up {
transform: rotate(-90deg);
}
&.more-search__icon--down {
transform: rotate(90deg);
}
}
}
</style>