概要
在我们的项目当中,无法避免会存在,列表显示数据量大的情况,如果在el-table中显示大量数据的话,就会导致浏览器卡死,所以可以使用本次提到的 el-table-v2虚拟化表格来解决数据量多的情况下列表卡顿的问题
一、安装elementPlus
npm i element-plus -s
二、el-table-v2的基本使用
elementPlus官网:跳转地址
1.官网示例
<template>
<el-table-v2
:columns="columns"
:data="data"
:width="700"
:height="400"
fixed
/>
</template>
<script lang="ts" setup>
const generateColumns = (length = 10, prefix = 'column-', props?: any) =>
Array.from({ length }).map((_, columnIndex) => ({
...props,
key: `${prefix}${columnIndex}`,
dataKey: `${prefix}${columnIndex}`,
title: `Column ${columnIndex}`,
width: 150,
}))
const generateData = (
columns: ReturnType<typeof generateColumns>,
length = 200,
prefix = 'row-'
) =>
Array.from({ length }).map((_, rowIndex) => {
return columns.reduce(
(rowData, column, columnIndex) => {
rowData[column.dataKey] = `Row ${rowIndex} - Col ${columnIndex}`
return rowData
},
{
id: `${prefix}${rowIndex}`,
parentId: null,
}
)
})
const columns = generateColumns(10)
const data = generateData(columns, 1000)
</script>
三、二次封装
子组件 :Virtualized_Table文件目录下的index.vue文件
<template>
<div class="tableV2 TableBox" >
<el-auto-resizer>
<template #default="{ height, width }">
<el-checkbox v-if="false" @change="handelAllShow" v-model="checked2">展开全部</el-checkbox>
<el-table-v2
:columns="columns"
v-loading="Tablloading"
:data="Tabledata||[]"
:default-expanded-row-keys="expandedRowKeys"
:expanded-row-keys="expandedRowKeys"
:estimated-row-height="50"
:expand-column-key="columns[0].key"
fixed
:width="width"
:height="
Comprops.PropVirtTableS.TableHeigth ||
400"
>
<template #row="props">
<Row v-bind="props" />
</template>
</el-table-v2>
</template>
</el-auto-resizer>
</div>
</template>
<script lang="tsx" setup>
import PublicAPI from "@/axios/public";
import {ref,reactive,defineProps,getCurrentInstance,watch} from 'vue'
//接收父组件传递过来的数据
const Comprops = defineProps(['PropVirtTableS'])
const proxy = getCurrentInstance()
//定义接收父组件传递过来的数据中 表头显示的对象
const TableHeaderTitle = reactive(Comprops.PropVirtTableS.keyS)
//定义接收父组件传递过来的数据中 列表显示的数据
const TableData = reactive(Comprops.PropVirtTableS.tables)
//展开全部
let checked2 = ref(false)
//存放展开全部的对象id
let expandedRowKeys = reactive([])
//处理接收到的表头的显示数据 并且根据父组件传递过来的数据,针对传递的类型,来判断是否显示其他的组件,比如下拉,输入框等等,此处只是简单的判断了,如果显示输入框,那么这一列都会是输入框,如果需要个别的显示,那么还需要加上其他条件。
function generateColumns(data:object){
let propsData = []
for (const key in data) {
let list = {}
list = {
key:key,
dataKey: data[key].children ? '' : key,
title: data[key].title,
//width: data[key].width ? data[key].width : 'auto', 这种表头如果多了,超出不显示,列表不会出现横向滚动条
width:150,//这种超出会出现滚动条
}
if(key === 'operate'){
list.cellRenderer = ({ cellData, rowData }) => {
// 假设 key 是在外部定义且可访问的
return data[key].children.map(item => {
let linkElement
if (item.type === 'delete') {
linkElement = <el-link onClick={() => {handelRowDelete(item,rowData)}} type="danger">删除</el-link>
}else if (item.type === 'edit') {
linkElement = <el-link type="primary">编辑</el-link>
}
return linkElement
})
}
}else if(data[key].type ) {
list.cellRenderer = ({ cellData, rowData }) => {
let linkElement
//显示输入框
if (data[key].type === 'input') {
linkElement = <ElInput modelValue={rowData[key]} onUpdate:modelValue = {(e)=>{rowData[key] = e} } value={rowData[key]} placeholder="Please input" />
}
//显示下拉
else if (data[key].type === 'select') {
linkElement = (
<ElSelectV2 multiple={true} options={data[key].children} disabled={ 1 === '1' } modelValue={rowData[key]} onUpdate:modelValue = {(e)=>{rowData[key] = e} }></ElSelectV2>
)
}
//显示计数器
else if (data[key].type === 'inputnumber') {
linkElement = (
<ElInputNumber controls-position="right" modelValue={rowData[key]} onUpdate:modelValue = {(e)=>{rowData[key] = e} }/>
)
}
return linkElement
}
}
propsData.push(list)
}
return propsData
}
//处理列表显示的数据
const generateData = (
columns: ReturnType<typeof generateColumns>,
length = TableData.length,
) =>
Array.from({ length }).map((_, rowIndex) => {
return columns.reduce(
(rowData, column, columnIndex) => {
if(column.dataKey){
//判断是否包含children :如果包含列表就会显示折叠展开嵌套数据
if(TableData[rowIndex].children){
rowData[column.dataKey].children = TableData[rowIndex].children
}else {
rowData[column.dataKey] = TableData[rowIndex][column.dataKey]
}
}
return rowData
},
{
id: rowIndex,
}
)
})
//列表的表头显示数据
const columns = generateColumns(TableHeaderTitle)
//列表显示的数据
let data = reactive(
//自定义添加children测试能否显示附加列表
generateData(columns, TableData.length).map((data) => {
data.children = [
{
id: `${data.id}-detail-content`,
detail: 11111,
},
]
return data
})
//嵌套的tab表头
const columnsRowChildren = reactive(generateColumns({
application_module: {
title: "物流供应商编号",
width:'200px'
},
business_code: {
title: "计费规则名称",
type:'input',
width:'200px'
},
operation_node: {
title: "计费仓库",
width:'200px'
},
operator_id: {
title: "物流供应商",
width:'200px'
},
operator_name: {
title: "物流公司",
width:'200px'
},
es_id: {
title: "状态",
width:'200px'
},
operate:
{
title:'操作',
width:'400px',
children: [
{
title: "编辑",
isshow: `buts.includes('system-users-role')`,
type: "edit",
},
{
title: "删除",
isshow: `buts.includes('system-users-delete')`,
type: "delete",
},
]
}
}))
//嵌套的tab数据 后期可以根据后端返回的数据来替换
const dataChildren = reactive([
{
application_module:'Acc200',
business_code:'御寒羽绒服1',
type:'上衣',
operation_node:'0.3456',
operator_id:'0.3456',
operator_name:'M-黑色',
es_id:'1',
},
{
application_module:'Acc200',
business_code:'御寒羽绒服1',
type:'上衣',
operation_node:'0.3456',
operator_id:'0.3456',
operator_name:'M-黑色',
es_id:'1',
},
{
application_module:'Acc200',
business_code:'御寒羽绒服1',
type:'上衣',
operation_node:'0.3456',
operator_id:'0.3456',
operator_name:'M-黑色',
es_id:'1',
},
])
//展开全部
function handelAllShow(value:boolean){
if(value) expandedRowKeys = data.map(item => item.id)
else expandedRowKeys = []
}
//判断返回渲染
const Row = ({ cells, rowData }) => {
//如果rowDate.detail存在就会显示嵌套的列表
if (rowData.detail) return <el-table-v2 class="nestElTableV2" data={dataChildren} columns={columnsRowChildren} width={900} height={200}></el-table-v2>
return cells
}
Row.inheritAttrs = false
//更新数据 页面列表数据不会刷新问题
watch(
() => Comprops.PropVirtTableS.tables,
(newValue) => {
data.splice(0, data.length);
data.push(...generateData(columns, newValue.length));
}
)
</script>
<style>
.el-table-v2__row-depth-0 {
height: 50px;
}
.el-table-v2__cell-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 展开的 子列表 */
.el-table-v2__row-depth-1{
width: 100%;
display: flex;
justify-content: center;
}
</style>
2:导出组件
//src -> components -> public -> Virtualized_Table -> index.vue 文件路径
import VirtualizedTable from "@/components/public/Virtualized_Table/index.vue";
export {
VirtualizedTable,
}
3.父组件传递的数据对象结构
父组件引用子组件
<template>
<VirtualizedTable v-if="PropVirtTableS.tables" :PropVirtTableS="PropVirtTableS" ></VirtualizedTable>
</template>
<script lang="ts" setup>
import {reactive} from 'vue'
import {VirtualizedTable} from "@/components";
//定义数据结构
let PropVirtTableS = reactive({
//自己定义的列表头显示数据 注意:application_module KEY值需要跟显示数据的KEY对应,否则此列数据显示不出来.
keyS: proxy.$PublicAPI.SetTableCotentWidth({
application_module: {
title: "物流供应商编号",
width:'200px'
},
business_code: {
title: "计费规则名称",
width:'200px'
},
operation_node: {
title: "计费仓库",
width:'200px'
},
operator_id: {
title: "物流供应商",
width:'200px'
},
operator_name: {
title: "物流公司",
width:'200px'
},
es_id: {
title: "状态",
width:'200px'
},
operate:
{
title:'操作',
width:'400px',
children: [
{
title: "编辑",
isshow: `buts.includes('system-users-role')`,
type: "edit",
},
{
title: "删除",
isshow: `buts.includes('system-users-delete')`,
type: "delete",
},
]
}
})
});
请求后端数据,将数据传递给组件
function GetTabList(params: object) {
// 调用列表数据
logapi.GetLogList(params).then((res) => {
PropVirtTableS.tables = res.data.list;
})
}
</script>
效果图: