Antd-Vue 封装表格防卡顿多数据滚动
1、如果antd的table加载几千条数据,会滚动卡顿、勾选也会卡顿,所以在table上写一个模拟的div,模拟表格的滚动,每次滚动 或者 首次加载 ROWS (默认15)条数据。
·
需求前提:
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
}
]
}
}
}
更多推荐
已为社区贡献4条内容
所有评论(0)