Antd-Vue 封装表格防卡顿多数据滚动

需求前提:

1、如果antd的table加载几千条数据,会滚动卡顿、勾选也会卡顿,所以在table上写一个模拟的div,模拟表格的滚动,每次滚动 或者 首次加载 ROWS (默认15)条数据。

2、因为创建了一个模拟的div,那实际我们鼠标移上去其实不是为table的基础div,是我们创建的div,所以用定时器处理保留了 table的鼠标移上去每行变颜色, 保存了键盘上下左右table滚动的方法,和表格中可点击项

3、优化了排序(前端处理的排序大小)

代码:

1、封装的tableScroll 代码 (vue-Mixin)

import { deepClone } from '@/utils/util'

const ROWS = 15,          // 局部渲染的数据条数
      HEIGHT = 38,      // 每行的高度
      TABLEHEIGHT = ROWS * HEIGHT;  // 表格可视高度
let tabs, tableScroll, timer, timer2, timer3, offsetHeight;

export const TableScroll = {
  data() {
    return {
        sortOrder: '',             // 排序的参数
        tableData: [],             // 当前表格显示的数据 (rows条)
        selectedRowKeys: [],       // 选择数据项
        dataSource: [],            // 表格全部数据
        defaultSource: [],         // 用于记录首次加载数据的排序 (排序恢复)
        rows: ROWS,                // 屏幕显示条数
        rowHeight: HEIGHT,         // 每条显示的高度
        tableHeight: TABLEHEIGHT,  // 数据总高度
        totalHeight: TABLEHEIGHT,  // 数据总高度
        idx: 0,                    // 当前开始下标
    }
  },
  watch: {
    getColums () {
     this.$nextTick(() => this.getOperaStatus())
    },
    dataSource() {

      const {
        dataSource,
        rows,
        rowHeight
      } = this

      // 设置序号
      let dataSourceList = this.dataSource.map((item, i) => {
        item.index = i + 1
        return item
      })
      // 清空勾选
      this.selectedRowKeys = []

      this.tableData = dataSourceList.length > rows ? dataSourceList.slice(0, rows) : dataSourceList
      this.totalHeight = dataSourceList.length * rowHeight  - 15
        // 控制虚拟滚动条
        this.$nextTick(() => {

          tabs = document.querySelector('.main .ant-tabs-tabpane.ant-tabs-tabpane-active') ? '.ant-tabs-tabpane.ant-tabs-tabpane-active' : '';
          // 移除滚动事件
          document.querySelector(`${tabs} .c-large-table .sc`).removeEventListener('scroll', ()=>{})
          // 设置上下滚动,滚动加载
          document.querySelector(`${tabs} .c-large-table .sc`).addEventListener('scroll', this.handleScroll);

          offsetHeight = document.querySelector(`${tabs} .c-large-table .ant-table-thead`).offsetHeight;

          this.tableHeight = this.$refs.table.offsetHeight - offsetHeight - 15

          document.querySelector(`${tabs} .c-large-table .table-sc`).style.display = (this.tableData.length === 0 || (this.totalHeight <= this.tableHeight)) ? 'none' : 'block'
          
          document.querySelector(`${tabs} .c-large-table`).style.paddingRight = (this.tableData.length === 0 || (this.totalHeight <= this.tableHeight)) ? '0' : '9px'
          
          document.querySelector(`${tabs} .c-large-table .sc`).style.top = offsetHeight + 'px'

          document.querySelector(`${tabs} .c-large-table .scbb`).style.height = offsetHeight + 'px'
          
          document.querySelector(`${tabs} .c-large-table .sc`).style.left = '98%';

          // 恢复滚动到表头部
          document.querySelector(`${tabs} .c-large-table .sc`).scrollTop = 0

          tableScroll = document.querySelector(`${tabs} .c-large-table .ant-table-scroll`);
          // 移除滚动事件
          tableScroll && tableScroll.removeEventListener('scroll', ()=>{});
          // 添加左右滚动,设置表格固定项是否固定
          tableScroll && tableScroll.addEventListener('scroll', (e) => {
              const {
                  scrollLeft
              } = e.target
              this.handleScrollLeft(scrollLeft)
          })

          tableScroll && this.handleScrollLeft(tableScroll.scrollLeft)

          this.getOperaStatus()

          // 处理虚拟键盘、虚拟滚动事件
          this.handleVirtualEvent()
        })
    }
  },

  created() {
    const {
      dataSource,
      rows,
      rowHeight
    } = this
    this.tableData = dataSource.length > rows ? dataSource.slice(0, rows) : dataSource
    this.totalHeight = dataSource.length * rowHeight

  },
  mounted() {
    

    window.addEventListener('resize', () => {
      this.getOperaStatus()
    })
  },
  methods: {
    onShowSizeChange(current, pageSize) {
      this.$emit("onShowSizeChange", current, pageSize);
    },
    pageChange(current, pageSize) {
      this.$emit("onChange", current, pageSize);
    },
    handleTableChange(e, filters, sorter) {
      console.log(e, filters, sorter)
    },
    // 表格自定义排序
    handleTableSortChange (selectedRowKeys, filters, sorter) {
      this.sortOrder = sorter.order;
      // 如果是升序
      if (sorter.order === 'ascend') {
        this.dataSource.sort(function (a, b) {
          return a[sorter.field] - b[sorter.field]
        })
      // 降序
      } else if (sorter.order === 'descend') {
        this.dataSource.sort(function (a, b) {
          return b[sorter.field] - a[sorter.field]
        })
      // 恢复正常
      } else {
        this.dataSource = deepClone(this.defaultSource)
      }
      
      // 如果有此参数
      if (this.queryParam && sorter.order) {
        this.queryParam.orderBy = sorter.field
        this.queryParam.sort = sorter.order === 'descend' ? 1 : 0;
      } else {
        delete this.queryParam.orderBy
        delete this.queryParam.sort
      }

      // 找到dataIndex
      this.$nextTick(() => {
        // 动态设置排序方式
        this.columns = this.columns.map(item => {
          item.sortOrder = item.dataIndex === sorter.field ? sorter.order : ''
          return item
        })
        this.columns.splice(0, 0)
        
      })
    },
    // 选项选择监听
    handleSelectChange(selectedRowKeys) {
      this.selectedRowKeys = selectedRowKeys
    },
    // 注意全选,需要手动填充数据
    handleSelectAll(d, dl) {
      let keys = [],
        dates = []
      // 全选
      if (d) {
        keys = this.dataSource.map(item => item.id)
        dates = [...this.dataSource]
      // 取消全选
      } else {
        keys = [];
        dates = [];
      }
      this.handleSelectChange(keys, dates)
    },
    // 配置选项
    getCheckboxProps (record) {
      console.log(record, '---record')
    },
    // 监听虚拟滚轮变化,计算展示的数据
    handleScroll(e) {
      let {
        scrollTop,
        scrollHeight
      } = e.target
      scrollTop = Math.ceil(scrollTop)
      let lenMax = this.dataSource.length,
        nIdx;
      if (scrollTop === 0) {
        this.tableData = this.dataSource.slice(0, this.rows)
        this.idx = 0
      } else if (scrollTop === (scrollHeight - this.tableHeight)) {
        nIdx = (lenMax - this.rows) < 0 ? 0 : (lenMax - this.rows)
        this.tableData = this.dataSource.slice(nIdx, nIdx + this.rows)
        this.idx = nIdx
      } else {
        nIdx = Math.ceil(scrollTop * lenMax / scrollHeight)
        if (nIdx !== this.idx && nIdx <= (lenMax - this.rows)) {
          this.tableData = this.dataSource.slice(nIdx, nIdx + this.rows)
          this.idx = nIdx
        }
      }
      // 判断滚动到底部
      if (Math.ceil(scrollTop + this.tableHeight) >= scrollHeight) {
        nIdx = lenMax - 15;
        this.tableData = this.dataSource.slice(nIdx, nIdx + this.rows)
        this.idx = nIdx
      }
    },
    // 监听左右滚动
    handleScrollLeft ( scroll ) {
        document.querySelector(`${tabs} .c-large-table .ant-table-fixed`).style.display = scroll === 0 ? 'none' : 'block'
    },
    // 滚动条状态 - 判断操作项是否浮动
    getOperaStatus (  ) {
      let e = document.querySelector(`${tabs} .ant-table-row-cell-break-word.ant-table-row-cell-last`), clientWidth;
      if (e) {
        clientWidth = e.clientWidth;
        try {
          this.columns[this.columns.length - 1].fixed = parseFloat(this.columns[this.columns.length - 1].width) < clientWidth ? false : 'right'
          e.style.zIndex = 1
        } catch (error) {
          
        }
        
      }
    },
    // 处理悬浮框的处理
    handleVirtualEvent () {
      // 监听滚轮事件
      window.onmousewheel =  () => {
        // 清除定时器
        clearTimeout(timer)
        // 如果有表格数据
        if (this.tableData.length > 0) {
          document.querySelector(`${tabs} .c-large-table .sc`).style.zIndex = 90;
          // 恢复虚拟滚动div的宽度,使滚动功能重新生效
          document.querySelector(`${tabs} .c-large-table .sc`).style.left = 0;
        }
        // 安装定时器,滚动后取消虚拟滚动
        timer = setTimeout(() => {
          document.querySelector(`${tabs} .c-large-table .sc`).style.zIndex = 10;
          // 解决鼠标放上去,表格条颜色不变问题,主要 通过修改虚拟滚动div的宽度,来实现鼠标下是表格的内容,而不是滚动div
          document.querySelector(`${tabs} .c-large-table .sc`).style.left = '98%';
        }, 100)
      }

      // 监听鼠标移动事件
      window.onmouseout= (event) => {
        this.y = event.clientY;
      }

      // 监听键盘右箭头事件
      window.onkeydown= function(event){
        var e = event || arguments.callee.caller.arguments[0];
        // 左右箭头
        if (e && (e.keyCode === 39 || e.keyCode === 37)) {
          // 清除定时器
          clearTimeout(timer2)
          // 清除定时器
          clearTimeout(timer3)
          // 监听虚拟左右箭头
          let div = document.querySelector(`${tabs} .c-large-table .scbc`)
          // 如果在表格中
          if(this.y > Number(div.getBoundingClientRect().top)){
            let div = document.querySelector(`${tabs} .c-large-table .ant-table-scroll`)
            // 设置滚动最大值
            let scrollLeft = e.keyCode === 39 ? (div.scrollLeft + 60) : (div.scrollLeft - 60)
            scrollLeft = scrollLeft < 0 ? 0 : scrollLeft
            // 设置滚动动画
            timer3 = setInterval(() => {
              // 左滑和右滑判断条件不一样
              if (e.keyCode === 39 ? div.scrollLeft >= scrollLeft : (div.scrollLeft <= scrollLeft)) {
                clearTimeout(timer3)
                return
              }
              div.scrollLeft = e.keyCode === 39 ? (div.scrollLeft + 4)  : (div.scrollLeft - 4)
            }, 1)
          }
          // 安装定时器,滚动后取消左右箭头
          timer2 = setTimeout(() => {
            // 清除定时器
            clearTimeout(timer3)
          }, 100)
        }
    };
    }
  },
  destroyed () {
    window.onmousewheel = () => {}
    window.onkeydown = () => {}
    window.onmouseout = () => {}
    
  }
}

2、vue代码块

<template>
        <div class=" c-large-table" ref="table">
                <a-table 
                    bordered
                    size="small" 
                    id="custom-table-header"
                    :class="['rpa-table-header ']"
                    :columns="columns" 
                    :data-source="tableData" 
                    :pagination="false"
                    :rowKey="(r, i) => i"
                >

                </a-table>

                <!-- 虚拟滚动条 -->
                <div div class="table-sc">
                    <div class="sc" :style="{height: tableHeight+'px'}">
                    <div class="scbc" :style="{height: totalHeight+'px'}"></div>
                 </div>
                <div class="scbb"></div>
            </div>
       </div>
</template>

<style lang="less" scoped>
.rpa-table-header /deep/.ant-table-scroll {
  overflow-x: auto !important;
}
.c-large-table {
  position: relative;
  overflow: hidden;

  /deep/.ant-table.ant-table-scroll-position-left .ant-table-fixed-left {
    box-shadow: 6px 0 6px -4px rgba(0, 0, 0, 0.15);
  }
  // padding-right: 8px;
  .ant-table-thead > tr > th, .ant-table-tbody > tr > td {
    padding: 4px 10px;
  }

  /deep/ .ant-checkbox{
    position: relative;
    z-index: 55;
  }

  .table-sc{
    &:before{
      position: absolute;
      bottom:0;
      right:0;
      width: 8px;
      background: #f6f6f6;
      content: '';
      height: 17px;
      border-right: 1px solid #e8e8e8;
      border-bottom: 1px solid #e8e8e8;
    }

    
    
  }
  .sc {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    overflow-x: hidden;
    overflow-y: scroll;
    z-index: 10;
    border-right: 1px solid #e8e8e8;
    .scbc {
      border-radius: 2px;
      background-color: transparent;
    }
  }

  .scbb{
    position: absolute;
    right: 0;
    top: 0px;
    width: 8px;
    background: #f6f6f6;
    border-right: 1px solid #e8e8e8;
    border-top: 1px solid #e8e8e8;
  }

  /deep/ .ant-table-fixed-right{
    z-index: 14;
  }
  /deep/ .ant-table-fixed-left{
    z-index: 13;
  }
  /deep/ .ant-table-tbody .fix {
    >div, >a, >span, >em, >p{
      z-index: 13;
      position: relative;
    }
  }
  /deep/ .ant-table-fixed-columns-in-body.ant-table-selection-column {
    opacity: 0;
  }

  #custom-table-header /deep/ .ant-table-tbody .ant-table-row-cell-break-word {
    position: relative;
  }

  

}

</style>

3、js模块

import { TableScroll } from '@/mixins/TableScroll'

export default {
    mixins: [TableScroll],
    data () {
        return {
            columns: [                    //  表格配置项
                {
                    title: '序号',
                    dataIndex: 'index',
                    width: 80
                },
                {
                    title: '表格配置项1',
                    dataIndex: 'index',
                    width: 120
                }
            ]
        }
    }
}

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值