基于vue通过一个对象实现可配置筛选框组件

3,001 阅读2分钟

一个业务组件筛选框的封装,错漏之处,还请指出。

主要封装背景是很多不同的页面都用到了筛选框,但里面的筛选项没有复用性,于是乎想着通过一个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
    }

后续扩展

前端只需维护好具体的业务组件,可以通过后端返回数据进行处理成对应的对象,从而实现动态的筛选框配置。尤其是电商业务类的筛选。