解决数据量过大及内容复杂时造成的Table渲染滚动的卡顿问题
vxe-table官方文档
npm install xe-utils vxe-table@legacy
vex-table.vue
<template>
<div class="page">
<vxe-grid
class="mytable"
ref="xGrid2"
v-bind="gridOptions2"
:loading="loading"
:checkbox-config="{
checkField: 'checked',
labelField: '',
highlight: true,
checkRowKeys: checkRowKeys,
showHeader: true,
}"
@current-change="currentChangeEvent"
@checkbox-change="selectChangeEvent"
@checkbox-all="selectChangeEvent"
>
<template #rowInfoSlot="{ row }">
{{ row }}
</template>
</vxe-grid>
</div>
</template>
<script>
import Sortable from "sortablejs";
import VXETable from "vxe-table";
const columns = [
{
field: "",
type: "checkbox",
fixed: "left",
width: 50,
},
{
title: "商品",
field: "taoBabyInfo",
slots: { default: "rowInfoSlot" },
// fixed: "left",
align: "center",
minWidth: 300,
},
{
title: "日期",
field: "statisDate",
// fixed: "left",
align: "center",
width: 65,
},
];
export default {
props: {
dataSource: {
type: Array,
default: function() {
return [];
},
},
},
data() {
return {
$table: null, //table实例
loading: false,
checkRowKeys: [],
gridOptions2: {
border: true,
stripe: true, //斑马纹
// showFooter: true, //页脚
class: "sortable-column",
// resizable: true,
showOverflow: true, //虚拟滚动
keepSource: true,
height: 750, //固定高度
maxHeight: 750, //最大高度
columnConfig: {
useKey: true,
// minWidth: 400, //最小高度
},
rowConfig: {
isCurrent: true,
isHover: true,
height: 121, // 行高
keyField: "babyId[0]",
},
scrollX: {
enabled: false,
},
scrollY: {
gt: 100,
mode: "default", //滚动模式,鼠标滚轮触发,用于左右固定列的复杂表格,更加流畅
oSize: 5,
// scrollToTopOnChange: true,
},
// footerMethod: this.footerMethod,
// checkboxConfig: { checkField: "checked", labelField: "name" },
toolbarConfig: {
// custom: true,//列筛选
tableToolbar: true,
// zoom: true, //全屏
},
// mouseConfig: { selected: true },
columns,
},
};
},
created() {
this.columnDrop2();
},
mounted() {
this.$table = this.$refs.xGrid2;
},
beforeDestroy() {
if (this.sortable2) {
this.sortable2.destroy();
}
},
methods: {
currentChangeEvent({ row }) {
// console.log("行选中事件", row);
this.$emit("rowClicked", row.babyId[0]);
},
selectChangeEvent({ $table }) {
const records = $table.getCheckboxRecords();
console.info(`勾选${records.length}个树形节点`, records);
this.checkRowKeys = records;
this.$emit("selectChange", records);
},
columnDrop2() {
this.$nextTick(() => {
const $table = this.$refs.xGrid2;
this.sortable2 = Sortable.create(
$table.$el.querySelector(
".body--wrapper>.vxe-table--header .vxe-header--row"
),
{
handle: ".vxe-header--column",
onEnd: ({ item, newIndex, oldIndex }) => {
const { fullColumn, tableColumn } = $table.getTableColumn();
const targetThElem = item;
const wrapperElem = targetThElem.parentNode;
const newColumn = fullColumn[newIndex];
if (newColumn.fixed) {
const oldThElem = wrapperElem.children[oldIndex];
// 错误的移动
if (newIndex > oldIndex) {
wrapperElem.insertBefore(targetThElem, oldThElem);
} else {
wrapperElem.insertBefore(
targetThElem,
oldThElem ? oldThElem.nextElementSibling : oldThElem
);
}
VXETable.modal.message({
content: "固定列不允许拖动,即将还原操作!",
status: "error",
});
return;
}
// 获取列索引 columnIndex > fullColumn
const oldColumnIndex = $table.getColumnIndex(
tableColumn[oldIndex]
);
const newColumnIndex = $table.getColumnIndex(
tableColumn[newIndex]
);
// 移动到目标列
const currRow = fullColumn.splice(oldColumnIndex, 1)[0];
fullColumn.splice(newColumnIndex, 0, currRow);
$table.loadColumn(fullColumn);
},
}
);
});
},
},
};
</script>
<style scoped lang="less">
.page {
/*滚动条整体部分*/
.mytable ::-webkit-scrollbar {
background-color: #f00;
width: 15px;
height: 15px;
}
/*滚动条的轨道*/
.mytable ::-webkit-scrollbar-track {
background-color: #ffffff;
}
/*滚动条里面的小方块,能向上向下移动*/
.mytable ::-webkit-scrollbar-thumb {
background-color: #bfbfbf;
// border-radius: 5px;
border: 1px solid #f1f1f1;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
bottom: 0;
}
.mytable ::-webkit-scrollbar-thumb:hover {
background-color: #a8a8a8;
}
.mytable ::-webkit-scrollbar-thumb:active {
background-color: #787878;
}
/*边角,即两个滚动条的交汇处*/
.mytable ::-webkit-scrollbar-corner {
background-color: #ffffff;
}
.sortable-column .vxe-header--row .vxe-header--column.sortable-ghost,
.sortable-column .vxe-header--row .vxe-header--column.sortable-chosen {
background-color: #dfecfb;
}
.sortable-column .vxe-header--row .vxe-header--column.col--fixed {
cursor: no-drop;
}
::v-deep .vxe-table--render-default .vxe-cell {
padding: 0;
font-size: 12px;
}
::v-deep .vxe-body--column {
vertical-align: top;
}
::v-deep .vxe-header--column:not(.col--ellipsis) {
padding: 5px 0;
}
::v-deep .vxe-header--row th:nth-child(1),
::v-deep .vxe-body--row td:nth-child(1) {
font-size: 13px;
text-align: center;
display: flex;
justify-content: center;
& .vxe-checkbox--icon {
background-color: #fff;
}
}
::v-deep .vxe-header--row th:nth-child(n + 1):nth-child(-n + 3),
::v-deep .vxe-body--row td:nth-child(n + 1):nth-child(-n + 3) {
background-color: #fff9ce;
text-align: center;
}
::v-deep .vxe-header--row th:nth-child(n + 4):nth-child(-n + 13) {
color: #ffc480;
}
::v-deep .vxe-body--column.col--ellipsis:not(.col--actived) > .vxe-cell {
overflow: inherit;
}
::v-deep .vxe-table--body-wrapper {
min-height: 155px;
}
}
</style>
index.vue
<template>
<VxeTable
ref="vxeTableRef"
@rowClicked="rowClicked"
@selectChange="rowSelected"
/>
</template>
<script>
import VxeTable from "./components/vxe-table/index.vue";
import { reportExcelPageList } from "@/services/user";
export default {
components: { VxeTable },
methods: {
rowClicked(row) {
console.log("🚀row", row);
},
rowSelected(row) {
console.log("🚀row", row);
},
async apiGetList(flag = true) {
const _vxeTableRef = this.$refs.vxeTableRef;
_vxeTableRef.loading = true;
await reportExcelPageList(this.query)
.then((e) => {
const { code, data, total } = e.data;
if (code === 0) {
let dataSource = [];
dataSource = this.restructure(data || []);
this.total = total;
// console.log("🚀🚀", dataSource);
//1.虚拟滚动渲染异步加载
_vxeTableRef.$table.reloadData(dataSource).then(() => {
if (flag) {
// 1.1 滚动到顶部
_vxeTableRef.$table.scrollTo(0, 0);
}
});
_vxeTableRef.loading = false;
}
})
.finally(() => {
_vxeTableRef.loading = false;
});
},
},
};
</script>
<style lang="less" scoped>
@import "index.less";
</style>