一个业务组件筛选框的封装,错漏之处,还请指出。
主要封装背景是很多不同的页面都用到了筛选框,但里面的筛选项没有复用性,于是乎想着通过一个js来配置筛选框,从而解决问题。最终可以通过引入一个mixin、一个筛选框组件、一个筛选框配置的对象,三部曲来实现筛选框。支持的功能有选项延后赋值、控制显隐、联动选择。组件库为vant。
实现思路(vue2为例)
vue3代码参考github.com/hhd5206/vue…
- 调用
<filter-popup
v-model="filterShow"
:filterRenderMap="filterRenderMaps"
@updateFilterRenderMap="updateFilterRenderMap"
@onLinkage="handleLinkage"
@confirm="onFilterConfirm" />
- 配置js的数据结构
// 对象的key直接为要跟后台的传参key
weight: {
title: '重量', // 标题
columns: [], // 配置项
value: undefined, // 传后端的值
text: undefined, // 页面反显值
component: ItemPicker, // 渲染的对应组件 实际的业务组件
extraOptions: { // 额外参数 根据具体封装的组件来配置
isRadio: true,
showSearch: true,
valueKey: 'dictValue',
textKey: 'dictText'
}
}
mixins: [filterMixin(filterRenderMap)]
引入filterMixin传入配置的filterRenderMap。 参数解释: filterShow: 控制显隐 filterRenderMap: 配置的js对象 updateFilterRenderMap: 更新配置的js对象绑定的vulue和text onLinkage: 处理联动逻辑 confirm: 筛选框确认后处理逻辑 最终在提交时传filterQueryParams
- filterMixin
const filterMixin = (filterRenderMap) => ({
data() {
return {
filterRenderMaps: deepClone(filterRenderMap), // 筛选框配置项
filterShow: false, // 筛选框显隐
filterQueryParams: {}, // 筛选框条件
}
},
methods: {
// 筛选确认
onFilterConfirm(params) {
this.filterQueryParams = params
},
updateFilterRenderMap(key, value) {
this.filterRenderMaps[key].value = value
this.filterRenderMaps[key].text = value
}
},
})
- 筛选框组件
- 通过遍历配置的filterRenderMap,配合vue内置的component组件进行组件的渲染。
<template v-for="(item, key) in filterRenderMap">
<template v-if="!item.isNotRender">
<component :is="item.component" v-show="isComponentShow(item.linkage, key)"
:key="key" :title="item.title" :columns="item.columns" :value.sync="item.value"
:text.sync="item.text" v-bind="item.extraOptions">
</component>
</template>
</template>
- 显隐处理
isPopupShow: {
get() {
return this.popupShow
},
set(val) {
this.$emit('change', val)
// 对比值有没有变化从而发不发起请求
if (
isActivesEquals(
this.filterQueryParams,
this.lastFilterQueryParams
)
) { return }
this.$emit('confirm', this.filterQueryParams)
},
}
- 控制联动关系的显隐
isComponentShow() {
return (linkage, key) => {
if (!linkage) return true
const parentVal = this.filterQueryParams[linkage.to]
if (parentVal) {
this.$emit(`onLinkage`, { key, parentVal, ...linkage })
} else {
this.onResetByKey(key)
}
return !!parentVal
}
}
- 返回处理筛选的条件
filterQueryParams() {
const obj = {}
const { filterRenderMap } = this
Object.keys(filterRenderMap).forEach((key) => {
const item = filterRenderMap[key]
const value = item.value
if (!item.isNotRender && (Array.isArray(value) ? value.length : value)) {
const splitKeyArray = key.split('&&') //支持一个key对应多字段 用&&拼接
if (splitKeyArray.length === 1) {
obj[key] = value
} else {
const splitValueArray =
value && value.split('&&')
splitValueArray &&
splitKeyArray.forEach((skey, index) => {
obj[skey] = splitValueArray[index]
})
}
}
})
return obj
}
- 业务组件&配置js 具体参考 github.com/hhd5206/vue… components文件夹及demo.js
后续扩展
前端只需维护好具体的业务组件,可以通过后端返回数据进行处理成对应的对象,从而实现动态的筛选框配置。尤其是电商业务类的筛选。