背景阐述:
原始代码中使用vue-easytable表格实现的可编辑表格,当前端进行大数据分页以及单页超过100条时,多次切换页码、单页显示数量时,出现浏览器崩溃问题。
问题定位:
首先思考是否是因为内存泄露导致的,所以用chorme任务管理去监听该页面的缓存占用情况,启动数据缓存时,发现还是会有这种情况,最后发现因为数据过多时,大量可编辑数据,计算过多占用的CPU过高导致的。
处理流程:
方案一:
首先想到虚拟滚动,只渲染当前可视区域表格数据,同时该组件也自带虚拟滚动功能,实施时发现即使设置缓存区域bufferScale,但滚动过快时会出现页面空白,同时因为每次滚动时都会重新计算当前渲染区域的表格每列使用什么组件【输入框、选择框等】,会导致滚动条卡顿,最后放弃该方案。
方案二:
想到点击该行任意单元格激活该行的编辑功能,计算该行每列的组件,不放置编辑按钮开启编辑功能是因为考虑之前版本一直是进来就直接操作,调整成点击每行具体按钮开启编辑功能,会给客户带来麻烦的体验,所以最终选定任意单元格开启该行编辑功能,这样页面中多条数据时也是只计算当前激活行的每列数据组件,降低了计算量。
代码示例:
<template>
<ve-table
rowKeyFieldName="id"
:columns="tableColumns"
:table-data="tableData" />
</template>
<script setup>
import {ref, onMounted } from "vue";
export default {
const columns = [
{
key: "colA",
label: "一列",
components: "a-select",
},
{
key: "colB",
label: "二列",
components: "a-input",
}
]
const tableColumns = ref([]);
const tableData = ref([]);
const editIndex = ref(null);
const getCompValue = (val, item) => {
let res;
if (!val && val !== 0) {
res = val;
} else if (item.component === 'a-checkbox') {
res = val.target.checked;
} else {
res = val.target?.tagName ? val.target.value : val;
}
return res;
},
const renderEditCell = ({ row, column, tempRowIndex }) => {
let _this = this
const rowIndex = tempRowIndex;
let Comp = column.component || 'a-input';
column.editAttr = column.editAttr || {};
const listeners = {
change: val => {
row[column.key] = getCompValue(val, column);
column.change &&
column.change({
value: val,
record: row[rowIndex],
index: rowIndex,
});
},
blur: val => {
let result = row[column.key];
if (typeof result === 'string' && !column.noTrim) {
row[column.key] = result.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}
column.blur &&
column.blur({
value: val,
record: row,
index: rowIndex,
});
},
};
if (column.editAttr.change) {
listeners.change = data => {
row[column.key] = data;
column.editAttr.change(data, rowIndex, row);
};
}
let itemDisabled = column.disabled || column.editAttr.disabled;
const dynamicBind = {
props: {
value: row[column.key],
options: column.options,
allowClear: true,
placeholder: column.placeholder,
disabled:
typeof itemDisabled === 'function'
? itemDisabled({ row, rowIndex })
: itemDisabled,
...(typeof column.editAttr === 'function'
? column.editAttr({ row, rowIndex })
: column.editAttr),
},
on: listeners,
};
if (column.component === 'a-checkbox') {
dynamicBind.props.checked = row[column.key];
}
return <Comp style="width:100%" {...dynamicBind}></Comp>;
};
const initColumns = () => {
tableColumns.value = columns?.map(cc => {
return {
...cc,
renderBodyCell: cc.key !== 'action' ? ({ row, column, rowIndex }, h) => {
let text = column?.component === ComponentSet.CHECKBOX ? row[column.key] ?
'是' : '否'
: row[column.key] || '--';
if (editIndex.value === rowIndex && column.component) {
return renderEditCell({ row, column, tempRowIndex: rowIndex })
} else {
return h('span', {
on: {
click: () => {
editIndex.value = rowIndex; // 点击改行任意键进入编辑模式;
}
},
style: { 'min-width': '200px', display: 'inline-block', height: '100%' }
}, text);
}
} : undefined,
}
});
}
onMounted(() => {
for(let i=0; i < 1000; i++) {
tableData.value.push({id: i + 1, colA: `${i}-AA`, colB: "xx"});
}
initColumns()
})
return {
tableData,
tableColumns,
}
}
</script>
上面的解决方案希望给大家一点灵感,欢迎大家指教