【vue2】在ant design vue的表格基础上进行多列筛选

工作中需要按照excel里面地表格筛选功能实现页面上的表格筛选功能,所以将相关代码记录下来便于后续翻看,实现效果如下。

html代码如下

<a-table
        :columns="columns"
        :dataSource="tableData"
        :pagination="false"
        bordered
        size="small"
        :scroll="{ x: 1940, y: 400 }"
        rowKey="key"
      >
        <template v-slot:filterDropdown="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }">
          <div class="filter-query">
            <a-input
              :value="selectedKeys[0]"
              style="min-width: 188px"
              @change="e => filterInputChange(e.target.value, setSelectedKeys, column.dataIndex)"
              @pressEnter="() => handleSearch(selectedKeys, confirm, column.dataIndex)"
            />
          </div>
          <div class="filter-list">
            <a-checkbox
              style="margin-left: 8px"
              :indeterminate="isIndeterminate(filterColList[column.dataIndex].selectedData, filterColList[column.dataIndex].dataList)"
              :checked="isChecked(filterColList[column.dataIndex].selectedData, filterColList[column.dataIndex].dataList)"
              @change="(e) => onCheckAllChange(e.target.checked, column.dataIndex)">
              {{ $t('f_title_selectAll') }}
            </a-checkbox>
            <a-checkbox-group
              :value="filterColList[column.dataIndex].selectedData"
              class="filter-list-item"
              name="checkboxgroup"
              :options="filterColList[column.dataIndex].dataList"
              @change="(keys) => filterChange(keys, column.dataIndex)"
            />
          </div>
          <div class="filter-query">
            <a-button
              type="primary"
              icon="search"
              size="small"
              style="width: 90px; margin-right: 8px"
              @click="() => handleSearch(selectedKeys, confirm, column.dataIndex)"
            >
              {{ $t('f_title_search') }}
            </a-button>
            <a-button size="small" style="width: 90px" @click="() => handleReset(selectedKeys, confirm, clearFilters, column.dataIndex, setSelectedKeys)">
              {{ $t('f_title_reset') }}
            </a-button>
          </div>
        </template>
        <a-icon
          slot="filterIcon"
          slot-scope="filtered, column"
          type="search"
          :style="{ color: getColor(column.dataIndex) }"
        />
      </a-table>

以下为js代码

初始化:

data () {
    return {
        columns: [
        {
          title: 'title1',
          dataIndex: 'title1',
          align: 'center',
          fixed: 'left',
          width: 120
        },
        {
          title: 'title2',
          dataIndex: 'title2',
          align: 'center',
          fixed: 'left',
          scopedSlots: {
            filterDropdown: 'filterDropdown',
            filterIcon: 'filterIcon',
            customRender: 'title2'
          },
          filterable: true,
          width: 150,
          onFilterDropdownVisibleChange: visible => {
            if (!visible) {
              this.catchDataInData('title2')
            }
          }
        },
        {
          title: 'title3',
          dataIndex: 'title3',
          align: 'center',
          fixed: 'left',
          scopedSlots: {
            filterDropdown: 'filterDropdown',
            filterIcon: 'filterIcon',
            customRender: 'title3'
          },
          filterable: true,
          width: 150,
          onFilterDropdownVisibleChange: visible => {
            if (!visible) {
              this.catchDataInData('title3')
            }
          }
        },
        {
          title: 'title4',
          dataIndex: 'title4',
          align: 'center',
          fixed: 'left',
          scopedSlots: {
            filterDropdown: 'filterDropdown',
            filterIcon: 'filterIcon',
            customRender: 'title4'
          },
          filterable: true,
          width: 150,
          onFilterDropdownVisibleChange: visible => {
            if (!visible) {
              this.catchDataInData('title4')
            }
          }
        },
        {
          title: '操作\nOperation',
          dataIndex: 'action',
          align: 'center',
          fixed: 'right',
          width: 120,
          scopedSlots: { customRender: 'action' }
        }
      ],
    }
},
created: {
    this.init()
},
methods: {
    init () {
        this.filterableArr = this.columns.filter(item => item.filterable)
      for (let i = 0; i < this.filterableArr.length; i++) {
        // 根据可以筛选的列,建立一个储存筛选信息的对象,key值为表格dataIndex
        this.filterColList[this.filterableArr[i].dataIndex] = {
          allDataList: [], // 当前列的所有数值
          dataList: [], // 当前展示的可操作的筛选checkboxList
          dataListCatch: [], // 储存dataList上一步操作的历史数据
          selectedData: [], // 当前展示的已选择的选项的value
          selectedDataCatch: [], // 储存selectedData上一步操作的历史数据
          cancelData: [], // 储存取消选择的checkbox对应的选项的value
          cancelDataCatch: [], // 储存cancelData上一步操作的历史数据
          changed: false // 表示当前列是否被筛选过的状态flag
        }
      }
    }
}

在获取表格数据之后,要再根据表格数据,填充filterColList中对应的数据

filterSet () {
      let allData = null
      for (let i = 0; i < this.filterableArr.length; i++) {
        allData = [...new Set(this.tableData.map(item => item[this.filterableArr[i].dataIndex]))].map(item => {
          return {
            label: item === null ? '空(null)' : item,
            value: item === null ? 'null' : item
          }
        })
        this.filterColList[this.filterableArr[i].dataIndex] = {
          allDataList: allData,
          dataList: allData,
          dataListCatch: allData,
          selectedData: allData.map(item => item.value),
          selectedDataCatch: allData.map(item => item.value),
          cancelData: [],
          cancelDataCatch: [],
          changed: false
        }
      }
    }

以下是table标签内的插槽中使用的方法

// 筛选下拉框中的输入框,在输入值发生变化后触发的方法,主要是用来筛选dataList数据,以及对应列的
// selectedData 数据,默认会把筛选出来的选项全部选中
filterInputChange (value, setSelectedKeys, dataIndex) {
      setSelectedKeys(value ? [value] : [])
      const temp = this.filterColList
      temp[dataIndex].dataList = temp[dataIndex].dataListCatch.filter(item => item.label.toString().indexOf(value) > -1)
      temp[dataIndex].selectedData = temp[dataIndex].dataList.map(item => item.value)
      temp[dataIndex].cancelData = value ? temp[dataIndex].allDataList.filter(item => item.label.toString().indexOf(value) === -1).map(item => item.value) : temp[dataIndex].allDataList.map(item => item.value)
      this.filterColList = Object.assign({}, this.filterColList, temp)
    }
// 判断全选checkbox是否是半选状态
isIndeterminate (value, list) {
      if (value.length > 0 && value.length < list.length) {
        return true
      } else {
        return false
      }
    },
// 判断全选checkbox是否选中
    isChecked (value, list) {
      if (value.length > 0 && value.length === list.length) {
        return true
      } else {
        return false
      }
    },
// 获取当前列的筛选icon的颜色,searchedColumn存储经过筛选操作的列的dataIndex
    getColor (dataIndex) {
      if (this.searchedColumn.indexOf(dataIndex) === -1) {
        return '#cccccc'
      } else {
        return '#108ee9'
      }
    },
// 在修改了列的筛选条件后,如果没有点击查询按钮,该方法会将存储的历史数据覆盖到当前因为筛选操作而被修改的dataList,selectedData,cancelData
    // 若是点击了查询按钮,在查询方法中便已经将存储的历史数据替换成当前筛选操作修改的数值了,因此就变再覆盖一遍也不会有变化
    catchDataInData (dataIndex) {
      setTimeout(() => {
        this.filterColList[dataIndex].dataList = [...this.filterColList[dataIndex].dataListCatch]
        this.filterColList[dataIndex].selectedData = [...this.filterColList[dataIndex].selectedDataCatch]
        this.filterColList[dataIndex].cancelData = [...this.filterColList[dataIndex].cancelDataCatch]
      })
    },
// 点击全选checkbox触发的方法和操作,主要是调整filterColList中储存的对应数据
onCheckAllChange (checked, dataIndex) {
      const temp = this.filterColList
      if (checked) {
        temp[dataIndex].selectedData = temp[dataIndex].allDataList.map(item => item.value)
        temp[dataIndex].cancelData = []
      } else {
        temp[dataIndex].cancelData = temp[dataIndex].allDataList.map(item => item.value)
        temp[dataIndex].selectedData = []
      }
      this.filterColList = Object.assign({}, this.filterColList, temp)
    }
// 点击查询按钮后触发的方法
handleSearch (selectedKeys, confirm, dataIndex) {
      confirm()
        // 通过判断cancelData中是否存值来判断是否经过筛选操作,因为只有点选过checkbox这个操作,才会在cancelData中存下数据
      setTimeout(() => {
        if (this.filterColList[dataIndex].cancelData.length === 0) {
          this.searchedColumn = this.searchedColumn.filter(item => item !== dataIndex)
        } else {
          if (this.searchedColumn.indexOf(dataIndex) === -1) {
            this.searchedColumn.push(dataIndex)
          }
        }
        setSelectedKeys([''])
      }, 0)
      const isReset = this.filterColList[dataIndex].selectedData.length === this.filterColList[dataIndex].allDataList.length
      // 同步暂存的修改前数据,只有在点击查询按钮后,筛选暂存的数据改为当前筛选数据
      this.filterColList[dataIndex].dataListCatch = [...this.filterColList[dataIndex].dataList]
      this.filterColList[dataIndex].selectedDataCatch = [...this.filterColList[dataIndex].selectedData]
      this.filterColList[dataIndex].cancelDataCatch = [...this.filterColList[dataIndex].cancelData]
    // 筛选源数据cacheData,cacheData是最初获取的表格的所有数据,要保证cacheData不能被修改
    // 筛选过程中,要注意判断dataIndex是当前筛选列的时候,要判断表格循环到的行的数据是否符合selectedData中的数据
    // 如果dataIndex不是当前列时,要通过判断当前行不在cancelData中来判断是否筛选出数据,不这样会导致下拉框中的dataList被筛选后,无法再回到筛选前的状态
      this.tableData = this.cacheData.filter(item => {
        for (const key in this.filterColList) {
          if (key !== dataIndex) {
            if (this.filterColList[key].cancelData.indexOf(item[key] === null ? 'null' : item[key]) > -1) {
              return false
            }
          } else {
            if (this.filterColList[key].selectedData.indexOf(item[key] === null ? 'null' : item[key]) === -1) {
              return false
            }
          }
        }
        return true
      })
      this.filterChangeProgress(dataIndex)
    },
// 根据表格筛选后的数据,重新填入filterColList中各个列存的筛选状态和数据
// 被筛选过的列,即便受到其他列筛选操作的影响,也要保证checklist中的选项不能减少,因此要根据是否
// changed 分别处理
    filterChangeProgress (dataIndex, isReset) {
      let allData = null
      let tempDataList = []
      this.filterColList[dataIndex].changed = !isReset
      for (let i = 0; i < this.filterableArr.length; i++) {
        allData = [...new Set(this.tableData.map(item => item[this.filterableArr[i].dataIndex]))].map(item => {
          return {
            label: item === null ? '空(null)' : item,
            value: item === null ? 'null' : item
          }
        })
        if (this.filterColList[this.filterableArr[i].dataIndex].changed) {
          tempDataList = this.getDataList(this.filterableArr[i].dataIndex)
          this.filterColList[this.filterableArr[i].dataIndex] = {
            allDataList: this.filterColList[this.filterableArr[i].dataIndex].allDataList,
            dataList: tempDataList,
            dataListCatch: tempDataList,
            selectedData: this.filterColList[this.filterableArr[i].dataIndex].selectedData,
            selectedDataCatch: this.filterColList[this.filterableArr[i].dataIndex].selectedDataCatch,
            cancelData: this.filterColList[this.filterableArr[i].dataIndex].cancelData,
            cancelDataCatch: this.filterColList[this.filterableArr[i].dataIndex].cancelDataCatch,
            changed: this.filterColList[this.filterableArr[i].dataIndex].changed
          }
        } else {
          this.filterColList[this.filterableArr[i].dataIndex] = {
            allDataList: this.filterColList[this.filterableArr[i].dataIndex].allDataList,
            dataList: allData,
            dataListCatch: allData,
            selectedData: this.filterColList[this.filterableArr[i].dataIndex].selectedData,
            selectedDataCatch: this.filterColList[this.filterableArr[i].dataIndex].selectedDataCatch,
            cancelData: this.filterColList[this.filterableArr[i].dataIndex].cancelData,
            cancelDataCatch: this.filterColList[this.filterableArr[i].dataIndex].cancelDataCatch,
            changed: this.filterColList[this.filterableArr[i].dataIndex].changed
          }
        }
      }
    },
// 根据除了当前筛选列以外的其他筛选列的筛选结果,确定当前列的可筛选项
getDataList (dataIndex) {
      const tempData = this.cacheData.filter(item => {
        for (const key in this.filterColList) {
          if (key !== dataIndex && this.filterColList[key].changed) {
            if (this.filterColList[key].cancelData.indexOf(item[key] === null ? 'null' : item[key]) > -1) {
              return false
            }
          }
        }
        return true
      })
      const res = [...new Set(tempData.map(item => item[dataIndex]))].map(item => {
        return {
          label: item === null ? '空(null)' : item,
          value: item === null ? 'null' : item
        }
      })
      return res
    }
// checkbox的change方法回调
filterChange (checkedValues, dataIndex) {
      const temp = this.filterColList
      temp[dataIndex].selectedData = checkedValues
      if (checkedValues.length === temp[dataIndex].allDataList.length) {
        temp[dataIndex].cancelData = []
      } else {
        const ts = temp[dataIndex].allDataList.filter(item => checkedValues.indexOf(item.value) === -1).map(item => item.value)
        temp[dataIndex].cancelData = ts
      }
      this.filterColList = Object.assign({}, this.filterColList, temp)
    }
// 重置功能
handleReset (selectedKeys, confirm, clearFilters, dataIndex, setSelectedKeys) {
      this.onCheckAllChange(true, dataIndex)
      this.handleSearch(selectedKeys, setSelectedKeys, confirm, dataIndex)
    }

写下来之后感觉或许会有优化的地方,也许之后有时间会看看能不能把代码再精简一下。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值