vxe-grid筛选渲染

表格数据过多时,需要过滤数据

在这里插入图片描述
代码:

// index.vue
<template>
  <div style="height: 400px">
    <vxe-grid ref="xGrid" v-bind="gridOptions"></vxe-grid>
  </div>
</template>
<script>
export default {
  data () {
    return {
      gridOptions: {
        highlightHoverRow: true,
        autoResize: true,
        height: 'auto',
        border: true,
        loading: false,
        editConfig: {
          trigger: 'dblclick',
          mode: 'cell',
          showStatus: true,
          showIcon: false,
          activeMethod: this.activeCellMethod
        },
        mouseConfig: {
          selected: true,
          area: true,
          extension: true
        },
        columns: [
          { type: 'seq' },
          {
            field: 'name',
            title: 'Name',
            filters: [{ data: '' }],
            filterRender: { name: 'FilterInput' }
          },
          {
            field: 'role',
            title: 'Role',
            editRender: { name: 'RoleCell', events: { click: this.getCellData } },
            filters: [{ data: { vals: [], sVal: '' } }],
            filterRender: {
              name: 'FilterContent'
            }
          },
          { field: 'sex', title: 'Sex' },
          {
            field: 'age',
            title: '年龄',
            filters: [{ data: { type: 'lt', name: '' } }],
            filterRender: { name: 'FilterComplex' }
          }
        ],
        data: []
      }
    }
  },
  mounted () {
    this.getData().then((data) => {
      this.gridOptions.data = data
    })
  },
  methods: {
    activeCellMethod () {
      return true
    },
    getCellData (params) {
      console.log(params)
    },
    getData () {
      return new Promise((resolve) => {
        const list = [
          { name: 'Test1', role: '前端', sex: '男', age: 13 },
          { name: 'Test2', role: '后端', sex: '男', age: 11 },
          { name: 'Test3', role: '测试', sex: '男', age: 15 },
          { name: 'Test4', role: '设计师', sex: '女', age: 12 },
          { name: 'Test5', role: '前端', sex: '男', age: 13 },
          { name: 'Test6', role: '前端', sex: '男', age: 16 },
          { name: 'Test7', role: '前端', sex: '男', age: 22 }
        ]
        resolve(list)
      })
    }
  }
}
</script>

// table.js 定义组件
VXETable.renderer.add('FilterContent', {
  // 不显示底部按钮,使用自定义的按钮
  isFooter: false,
  // 筛选模板
  renderFilter (h, renderOpts, params) {
    return [
      <filter-content params={ params }></filter-content>
    ]
  },
  // 重置数据方法
  filterResetMethod ({ options }) {
    options.forEach(option => {
      option.data = { vals: [], sVal: '' }
    })
  },
  // 筛选数据方法
  filterMethod ({ option, row, column }) {
    const { vals } = option.data
    console.log(vals)
    // eslint-disable-next-line no-undef
    let cellValue = XEUtils.get(row, column.property)
    if (column.property === 'customerItemCode') {
      cellValue = cellValue.customerItemCode || cellValue
    }
    return vals.includes(cellValue)
  }
})
// 条件过滤
VXETable.renderer.add('FilterComplex', {
  // 不显示底部按钮,使用自定义的按钮
  isFooter: false,
  // 筛选模板
  renderFilter (h, renderOpts, params) {
    const { events } = renderOpts
    return [
      <filter-complex params={ params } events={events}></filter-complex>
    ]
  },
  // 重置数据方法
  filterResetMethod ({ options }) {
    // console.log(options)
    options.forEach(option => {
      option.data = { type: 'lt', name: '' }
    })
  },
  // 筛选数据方法
  filterMethod ({ option, row, column }) {
    // console.log(option, row, column)
    const cellValue = parseFloat(XEUtils.get(row, column.property))
    // console.log(cellValue)
    const { name, type } = option.data
    if (!name) {
      return true
    }
    if (type === 'lt') {
      return cellValue < parseInt(name)
    } else if (type === 'eq') {
      return cellValue === parseInt(name)
    } else if (type === 'gt') {
      return cellValue > parseInt(name)
    }
    return false
  }
})
VXETable.renderer.add('FilterInput', {
  // 筛选模板
  renderFilter (h, renderOpts, params) {
    // console.log(params)
    return [
      <filter-input params={ params }></filter-input>
    ]
  },
  // 筛选方法
  filterMethod ({ option, row, column }) {
    const { data } = option
    const cellValue = row[column.property]
    if (cellValue) {
      return cellValue.indexOf(data) > -1
    }
    return false
  }
})

// 内置组件 FilterContent.vue
<template>
  <div class="my-filter-content">
    <div class="my-fc-search">
      <div class="my-fc-search-top">
        <vxe-input v-model="option.data.sVal" placeholder="搜索" @input="searchEvent" suffix-icon="fa fa-search"></vxe-input>
      </div>
      <div class="my-fc-search-content">
        <template v-if="valList.length">
          <ul class="my-fc-search-list my-fc-search-list-head">
            <li class="my-fc-search-item">
              <vxe-checkbox v-model="isAll" @change="changeAllEvent">全选</vxe-checkbox>
            </li>
          </ul>
          <ul class="my-fc-search-list my-fc-search-list-body">
            <li class="my-fc-search-item" v-for="(item, sIndex) in valList" :key="sIndex">
              <vxe-checkbox v-model="item.checked">{{ item.value }}</vxe-checkbox>
            </li>
          </ul>
        </template>
        <template v-else>
          <div class="my-fc-search-empty">无匹配项</div>
        </template>
      </div>
    </div>
    <div class="my-fc-footer" style="text-align: right">
      <vxe-button type="text" @click="confirmFilterEvent">筛选</vxe-button>
      <vxe-button style="margin-left: 0" type="text" @click="resetFilterEvent">重置</vxe-button>
    </div>
  </div>
</template>

<script>
import XEUtils from 'xe-utils'

export default {
  name: 'FilterContent',
  props: {
    params: Object
  },
  data () {
    return {
      size: 'mini',
      isAll: false,
      option: null,
      colValList: [],
      valList: []
    }
  },
  created () {
    this.load()
  },
  methods: {
    load () {
      const { $table, column } = this.params
      const { fullData } = $table.getTableData()
      const option = column.filters[0]
      const { vals } = option.data
      let colValList = Object.keys(XEUtils.groupBy(fullData, column.property)).map(val => {
        return {
          checked: vals.includes(val),
          value: val
        }
      })
      const columnsArr = []
      console.log(XEUtils.groupBy(fullData, column.property))
      if (column.property === 'customerItemCode') {
        fullData.forEach(item => {
        //   console.log(item['customerItemCode']['customerItemCode'])
          const toValue = item.customerItemCode.customerItemCode
          if (toValue) {
            columnsArr.push({
              checked: vals.includes(toValue),
              value: toValue
            })
          }
        })
        if (columnsArr && columnsArr.length) {
          colValList = columnsArr
        }
      }
      console.log(colValList)
      this.option = option
      this.colValList = colValList
      this.valList = colValList
    },
    searchEvent () {
      const { option, colValList } = this
      this.valList = option.data.sVal ? colValList.filter(item => item.value.indexOf(option.data.sVal) > -1) : colValList
    },
    changeAllEvent () {
      const { isAll } = this
      this.valList.forEach(item => {
        item.checked = isAll
      })
    },
    confirmFilterEvent (evnt) {
      const { params, option, valList } = this
      const { data } = option
      const { $panel } = params
      data.vals = valList.filter(item => item.checked).map(item => item.value)
      console.log(this.events)
      $panel.changeOption(evnt, true, option)
      $panel.confirmFilter()
    },
    resetFilterEvent () {
      const { $panel } = this.params
      $panel.resetFilter()
    }
  }
}
</script>

<style>
.my-filter-content {
  padding: 10px;
  user-select: none;
}
.my-filter-content .my-fc-search .my-fc-search-top {
  position: relative;
  padding: 5px 0;
}
.my-filter-content .my-fc-search .my-fc-search-top > input {
  border: 1px solid #ABABAB;
  padding: 0 20px 0 2px;
  width: 200px;
  height: 22px;
  line-height: 22px;
}
.my-filter-content .my-fc-search .my-fc-search-content {
  padding: 2px 10px;
}
.my-filter-content .my-fc-search-empty {
  text-align: center;
  padding: 20px 0;
}
.my-filter-content .my-fc-search-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.my-filter-content .my-fc-search-list-body {
  overflow: auto;
  height: 120px;
}
.my-filter-content .my-fc-search-list .my-fc-search-item {
  padding: 2px 0;
  display: block;
}
.my-filter-content .my-fc-footer {
  text-align: right;
  padding-top: 10px;
}
.my-filter-content .my-fc-footer button {
  /* padding: 0 15px; */
  /* margin-left: 15px; */
}
.my-fc-search-content ul {
  text-align: left;
}
</style>

条件搜索过滤
在这里插入图片描述

// FilterInput.vue
<template>
  <div class="my-filter-input" style="text-align: right">
    <vxe-input type="text" v-model="option.data" placeholder="支持回车筛选" @keyup="keyupEvent" @input="changeOptionEvent"></vxe-input>
  </div>
</template>

<script>
export default {
  name: 'FilterInput',
  props: {
    params: Object
  },
  data () {
    return {
      column: null,
      option: null
    }
  },
  created () {
    this.load()
  },
  methods: {
    load () {
      const { column } = this.params
      const option = column.filters[0]
      this.column = column
      this.option = option
    },
    changeOptionEvent () {
      // console.log('输入')
      const { params, option } = this
      const { $panel } = params
      const checked = !!option.data
      $panel.changeOption(null, checked, option)
    },
    keyupEvent ({ $event }) {
      const { params } = this
      const { $panel } = params
      if ($event.keyCode === 13) {
        $panel.confirmFilter()
      }
    }
  }
}
</script>

<style scoped>
.my-filter-input {
  padding: 10px;
}
</style>

文本搜索过滤
在这里插入图片描述

// FilterComplex.vue
<template>
  <div class="my-filter-complex">
    <div class="my-fc-type">
      <vxe-radio v-model="option.data.type" name="fType" label="lt">小于</vxe-radio>
      <vxe-radio v-model="option.data.type" name="fType" label="eq">等于</vxe-radio>
      <vxe-radio v-model="option.data.type" name="fType" label="gt">大于</vxe-radio>

    </div>
    <div class="my-fc-name">
      <vxe-input v-model="option.data.name" type="text" placeholder="请输入数量" @input="changeOptionEvent()"></vxe-input>
    </div>
    <div class="my-fc-footer" style="text-align: right">
      <vxe-button :disabled="!option.data.name" type="text" @click="confirmEvent">筛选</vxe-button>
      <vxe-button style="margin-left: 0" type="text" @click="resetEvent">重置</vxe-button>
    </div>
  </div>
</template>

<script>
// import XEUtils from 'xe-utils'
export default {
  name: 'FilterComplex',
  props: {
    params: Object,
    events: Object
  },
  data () {
    return {
      size: 'mini', // 被所有子组件继承 size
      column: null,
      option: null
    }
  },
  created () {
    this.load()
  },
  methods: {
    load () {
      const { column } = this.params
      console.log(this.params)
      const option = column.filters[0]
      this.column = column
      this.option = option
    },
    changeOptionEvent () {
      console.log('输入')
      const { params, option } = this
      const { $panel } = params
      const checked = !!option.data.name
      $panel.changeOption(null, checked, option)
    },
    confirmEvent () {
      console.log(this.params)
      const { $panel, column } = this.params
      console.log(column)
      $panel.confirmFilter()
    },
    resetEvent () {
      // eslint-disable-next-line no-unused-vars
      const { $panel } = this.params
      $panel.resetFilter()
    }
  }
}
</script>

<style scoped>
.my-filter-complex {
  width: 260px;
  padding: 5px 15px 10px 15px;
}
.my-filter-complex .my-fc-type {
  padding: 8px 0;
}
.my-filter-complex .my-fc-footer {
  text-align: center;
}
</style>

Number 类型过滤
在这里插入图片描述

Logo

前往低代码交流专区

更多推荐