element table 虚拟滚动 checkbox多选和全选处理

5,968 阅读1分钟

使用padding实现表格节点的虚拟滚动
代码示例为总数量500条,每次只渲染当前展示区域内的10条
直接粘完整代码

<template>
  <div class="new-component">
    <el-table
      ref="table"
      v-loading="listLoading"
      class="virtual-table"
      :data="virtualRows"
      :max-height="440"
      :row-key="getRowKeys"
      @select-all="handleSelectionAll"
    >
      <el-table-column type="selection" :reserve-selection="true" width="55" />
      <el-table-column prop="date" label="日期" min-width="180px" />
      <el-table-column prop="name" label="姓名" min-width="180px" />
      <el-table-column prop="address" label="地址" min-width="180px" />
    </el-table>
  </div>
</template>

<script>
import { debounce } from 'throttle-debounce'
export default {
  data() {
    return {
      tableData: [],
      virtualRows: [],
      listLoading: false,
      selectedAllStatus: false,
      selectedRow: [],
      selectedRowIds: []
    }
  },
  created() {
    for (let i = 0; i < 100; i++) {
      this.tableData.push({
        id: i,
        date: i,
        name: 'i' + i,
        address: i + '-' + i + '-' + i + '-' + i
      })
    }
    this.throttleResize = debounce(100, () => {
      this.handleScroll()
    })
  },
  beforeMount() {},
  mounted() {
    this.addListeners()
    this.updateVisibleItems()
  },
  beforeDestroy() {
    this.removeListeners()
  },
  methods: {
    // 对table增加监听事件
    addListeners() {
      if (!this.$refs.table.bodyWrapper) {
        return
      }
      this.$refs.table.bodyWrapper.addEventListener('scroll', this.throttleResize)
    },
    removeListeners() {
      if (!this.$refs.table.bodyWrapper) {
        return
      }
      this.$refs.table.bodyWrapper.removeEventListener('scroll', this.throttleResize)
    },
    handleScroll() {
      console.count('处理滚动事件')
      this.updateVisibleItems()
    },
    updateVisibleItems() {
      const itemSize = 40 // td高度
      const count = this.tableData.length // table总条数
      const bufferCount = 10 // table每次实际渲染条数
      const height = count * itemSize

      // 获取当前滚动条位置
      const scroll = this.getScroll()
      const scrollTop = scroll.start

      // Fixed size mode
      let startIndex
      startIndex = ~~(scrollTop / itemSize)
      startIndex < 0 && (startIndex = 0)
      // 分隔数组
      this.virtualRows = this.tableData.slice(startIndex, startIndex + bufferCount)

      // 设置el-table上的虚拟列表,采用了padding的方案,原因是transform 会使el-table的样式混乱
      const mainTable = this.$refs.table.$el.getElementsByClassName('el-table__body')
      Array.from(mainTable).forEach(table => {
        table.style.height = height + 'px'
        if (startIndex + bufferCount >= count) {
          // 由于el-table 在滚动到最后时,会出现抖动,因此增加判断,单独设置属性
          table.style.paddingTop = scrollTop - itemSize + 'px'
          table.style.paddingBottom = 0
        } else {
          table.style.paddingTop = scrollTop + 'px'
          table.style.paddingBottom = height - scrollTop - bufferCount * itemSize + 'px'
        }
      })

      // 切换选中状态
    },
    getScroll() {
      if (!this.$refs.table.bodyWrapper) {
        return {
          start: 0,
          end: 400
        }
      }
      const dom = this.$refs.table.bodyWrapper
      const scrollState = {
        start: dom.scrollTop,
        end: dom.scrollTop + dom.clientHeight
      }
      return scrollState
    },
    handleSelectionAll(selection) {
      this.selectedAllStatus = !this.selectedAllStatus
      const refsElTable = this.$refs.table // 获取表格对象
      const tableDataLength = this.tableData.length
      if (this.selectedAllStatus) {
        console.log('选中所有行')
        refsElTable.clearSelection() // 先清空
        for (let index = 0; index < tableDataLength; index++) {
          // 选中所有行
          refsElTable.toggleRowSelection(this.tableData[index], true)
        }
      } else {
        console.log('清空选中所有行')
        refsElTable.clearSelection()
      }
    },
    getRowKeys(row) {
      return row.id // 设定每一条对应一个key
    }
  }
}
</script>

<style  scoped>
::v-deep.el-table th {
  background: #f4f4f4 !important;
  height: 40px !important;
  padding: 0 0 !important;
}
::v-deep.el-table td {
  height: 40px !important;
  padding: 0 0 !important;
}
</style>

参考网址: blog.csdn.net/j_bleach/ar…