Skip to content

vxe-table 二次封装(筛选 + 排序 + 分页)(1)

场景需求

  • 在vxe-table的基础上,增加对排序和筛选的配置
  • 同时增加对分页的支持
  • 技术栈:vue2 + vxe-table@3.8.22

基本调研

注意:本次使用 v3.8版本,现在已经不维护了(只做封装思路参考)

实现思路

排序配置

排序配置比较简单

  • 配置:
    • 在 VxeColumn 组件的 sortable 设置为true <VxeColumn :sortable="true"></VxeColumn>
  • 触发:
    • 在 VxeTable 组件上,监听 sort-change 事件,获取排序参数数据 <VxeTable @sort-change="sortChange>
    • 存在多列触发排序的情况,排序参数数据返回是多条,其中排序类型 order:正序 asc 倒序 desc

筛选配置

筛选配置相对复杂

配置1:注册筛选组件

  • 1、需要 VXETable.renderer.add(BaseFilterRenderName, filterConfig) 注册一个筛选配置
js
VxeTablePlus.install = function install(Vue) {
  VXETable.renderer.add(BaseFilterRenderName, filterConfig)
  Vue.component(VxeTablePlus.name, VxeTablePlus)
}
  • 2、filterConfig如下
jsx
export const filterConfig = {
  showFilterFooter: false,
  renderFilter(h, { attrs, props }, params) {
    // 注冊筛选组件
    return <TableFilter {...{ attrs, props }} scope={params} />
  },
  // 重置数据方法
  filterResetMethod({ column, options }) {
    for (const option of options) {
      option.data = getColumnDefaultFilterData(column)
    }
  },
  // 筛选方法
  filterMethod({ cellValue, option }) {
    // 这里的注意点:
    // 如果设置为remote = true,$panel.confirmFilter()调用时,这里不会触发
    return filterValue(cellValue, option.data)
  },
}
  • 3、TableFilter 筛选组件如何构造

    • 筛选组件数据来源

      js
      // 配置数据
      const { $table, column } = this.scope
      this.option = column.filters[0]?.data
        ? column.filters[0]
        : {
            data: getColumnDefaultFilterData(column),
          }
    • 筛选选项控制(核心点)

      • 确认筛选数据的类型 option.data.valueType 包括:数字、字符串、日期时间类(日期、时间、日期时间)
      • 根据筛选数据的类型,获取对应控制下拉对比条件 condition
      js
      const conditions = defaultConditions[this.valueType ?? 'default'] ?? []
      • 根据筛选数据的类型,渲染对应组件
      js
      filterComponent() {
        if (this.isCustomOptions) {
          return TrTableFilterCustom
        }
      
        switch (this.valueType) {
          case 'date': {
            return TrTableFilterDate
          }
          case 'time': {
            return TrTableFilterTime
          }
          case 'datetime': {
            return TrTableFilterDateTime
          }
          case 'number': {
            return TrTableFilterNumber
          }
          default: {
            return TrTableFilterDefault
          }
        }
      },
    • 自定义了筛选按钮的逻辑

    js
    async handleFilter(evt) {
      try {
        await this.$refs.filter?.validate()
        const { $panel } = this.scope
        // 调用 vxe-table 筛选api,触发 vxe-table @filter-change事件
        $panel.changeOption(evt, true, this.option)
        $panel.confirmFilter()
      } catch (e) {
        console.log(e)
      }
    },
    • 自定义重置按钮的逻辑
    js
    handleReset() {
      const { $panel } = this.scope
      // 调用 vxe-table 重置api
      $panel.resetFilter()
    },

配置2:使用筛选组件

  • 1、在 VxeColumn组件 上配置 filter-render 和 filters
    • <VxeColumn :filter-render="getColumnFilterRender(column)" :filters="getColumnFilters(column)">
  • 2、filter-render 主要用来配置渲染器(对应筛选组件)
js
getColumnFilterRender(column) {
  if (!column.field || column.filters === false) return void 0

  const { props: filterRenderProps, ...restFilterRender } = column.filterRender ?? {}
  // debugger
  return {
    name: BaseFilterRenderName, // 关键点,指定渲染器名称
    ...restFilterRender,
    props: {
      // 如果传递了 filters 则将 filters 作为 options
      options: getColumnCustomValueOptions(column),
      multiple: column.filterMultiple ?? true,
      ...filterRenderProps,
    },
  }
},
  • 3、filters 配置筛选数据(筛选条件)
js
getColumnFilters(column) {
  if (!column.field || column.filters === false) return void 0

  let filters

  if (this.filtersMap[column.field]) {
    filters = this.filtersMap[column.field]
  } else {
    filters = [{ data: {} }]

    // 保证每次拿到的是同一个 filters 对象, 而不是每次都重新创建一个
    this.filtersMap[column.field] = filters
  }

  const data = filters[0].data
  // 参数设置
  data.valueType = getColumnFilterValueType(column)
  data.valueFormat = getColumnFilterValueFormat(column, data.valueType)
  // 默认值设置
  if (!data.condition) {
    data.condition = getDefaultFilterCondition(data.valueType)
  }

  if (data.value === undefined) {
    data.value = getDefaultFilterValue(data.valueType)
  }

  if (data.values === undefined) {
    data.values = getDefaultFilterValues(data.valueType)
  }

  return filters
},

到此,vxe-table 二次封装(筛选、排序)配置完毕

分页封装

  • <ElPagination /><VxeTable><VxeColumn />組件进行组合
  • <ElPagination />组件触发事件 emit 到最外层

注意点

  • VxeTable 插件注册
  • 需要二次封装组件和 vxe-table组件 同时注册,才能将配置渲染出来
js
import VxeTablePlus from './plugin/vxe-table-plus'
import VxeTable from 'vxe-table'

// 安装 VXETable 插件
Vue.use(VxeTablePlus)
Vue.use(VxeTable)

代码