1、业务背景

使用vue+element开发报表功能时,需要列表上某列的超链接按钮弹窗展示,在弹窗的el-table列表某列中再次使用超链接按钮点开弹窗,以此类推多表格弹窗嵌套,本文以弹窗两次为例

最终效果如下示例页面

2、具体实现和问题抛出

<template>
<div class="el_main">
<el-table
stripe
style="width: 100%"
v-loading="loading"
row-key="Id"
:data="list"
>
<el-table-column label="ID" prop="Id" min-width="3"> </el-table-column>
<el-table-column label="类型" prop="Type" min-width="5">
<template slot-scope="scope">
{{ formatTaskType(scope.row.Type) }}
</template>
</el-table-column>
<el-table-column label="详情" prop="TaskTitle" min-width="10" show-overflow-tooltip="true"></el-table-column>
<el-table-column
label="详情弹窗"
min-width="3">
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="text">查看</el-button>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="AddTime" min-width="5">
<template slot-scope="scope" v-if="scope.row.AddTime">
{{ (scope.row.AddTime * 1000) | formatDate(2) }}
</template>
</el-table-column>
</el-table>
</div>
<!-- 详情弹窗 -->
<el-dialog
title="详情弹窗"
:visible.sync="detailInfoDialogVisible"
append-to-body
width="50%">
<el-table
stripe
style="width: 100%"
v-loading="loading"
row-key="Id"
height="300" max-height="650"
:data="detailInfo">
<el-table-column label="ID" prop="TaskId" min-width="80"></el-table-column>
<el-table-column label="名称" prop="TaskName" min-width="65"></el-table-column>
<el-table-column label="成功数量" prop="SuccessNum" min-width="22"></el-table-column>
<el-table-column label="失败数量" prop="ErrorNum" min-width="22"></el-table-column>
<el-table-column label="状态列表" min-width="22">
<template slot-scope="scope">
<el-button @click="handleStatusListClick(scope.row)" type="text">查看</el-button>
</template>
</el-table-column>
<el-table-column label="队列列表" min-width="30">
<template slot-scope="scope">
<el-button @click="handleQueueDataClick(scope.row)" type="text">查看</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
<!-- 状态列表弹窗 -->
<el-dialog
title="状态弹窗"
:visible.sync="statusListDialogVisible"
append-to-body
width="30%">
<el-table
stripe
style="width: 100%"
v-loading="loading"
row-key="Id"
height="300" max-height="300"
:data="statusListInfo">
<el-table-column label="ID" prop="Id" min-width="80" show-overflow-tooltip="true"> </el-table-column>
<el-table-column label="标题" prop="Title" min-width="80" show-overflow-tooltip="true"></el-table-column>
<el-table-column label="返回信息" prop="Msg" min-width="80" show-overflow-tooltip="true"></el-table-column>
</el-table>
</el-dialog>
<!-- 队列列表弹窗 -->
<el-dialog
title="队列弹窗"
:visible.sync="queueDataDialogVisible"
append-to-body
width="30%">
<el-table
stripe
style="width: 100%"
v-loading="loading"
row-key="Id"
height="300" max-height="300"
:data="queueDataInfo">
<el-table-column label="ID" prop="Id" min-width="80" show-overflow-tooltip="true"> </el-table-column>
<el-table-column label="名称" prop="Name" min-width="80" show-overflow-tooltip="true"></el-table-column>
</el-table>
</el-dialog>
</template> <script type="text/ecmascript-6">
import { GetXXXReportList, ExportXXXReportList } from '@/api/reportManage' const urlQuery = [
'id|number',
'type|number',
'currPage|number',
'pageSize|number',
] export default {
components: {
}, data () {
return {
id: '',
type: '',
collectTime: '',
loading: false,
list: [],
currPage: 1,
pageSize: 10,
counts: 0,
detailInfo: [], // 详情弹窗
detailInfoDialogVisible: false,
statusListInfo: [], // 状态列表弹窗
statusListDialogVisible: false,
queueDataInfo: [], // 队列列表弹窗
queueDataDialogVisible: false,
typeArray: [
{
value: 1,
label: '类型一',
},
{
value: 2,
label: '分类二',
},
{
value: 3,
label: '分类三',
},
{
value: 4,
label: '分类四',
},
{
value: 5,
label: '分类五',
},
{
value: 6,
label: '分类六',
},
],
exportLoading: false,
}
},
created () {
this._getList(true)
},
methods: {
async _getList (init = false) {
this.loading = true
if (init) {
this.currPage = 1
}
let startTime, endTime
if (this.collectTime) {
startTime = this.collectTime[0] / 1000
endTime = this.collectTime[1] / 1000 + 86399
}
this._setQuery(urlQuery)
try {
const data = await GetXXXReportList({
Id: this.id || 0,
StartTime: startTime || 0,
EndTime: endTime || 0,
Type: this.type || 0,
CurrPage: this.currPage,
PageSize: this.pageSize,
})
this.list = data.List
this.counts = data.Counts
} catch (error) {
this.counts = 0
this.list = []
}
this.loading = false
},
search () {
this._getList(true)
},
reset () {
this.id = ''
this.type = ''
this.collectTime = ''
this.list = []
this.counts = 0
this._getList(true)
},
pageChange () {
this._getList()
},
pageSizeChange (val) {
this.pageSize = val
this._getList(true)
},
handleClick (row) {
if (row.Type === 1) {
this.detailInfoDialogVisible = true
this.detailInfo = row.detailInfo
} else if (row.Type === 2) {
this.xxxDialogVisible = true
this.xxxInfo = row.xxx
} else if (row.Type === 3) {
this.xxxDialogVisible = true
this.xxxInfo = row.xxx
}
},
handleStatusListClick (row) {
this.statusListDialogVisible = true
this.statusListInfo = row.StatusList
},
handleQueueDataClick (row) {
this.queueDataDialogVisible = true
this.queueDataInfo = row.queueData
},
// 导出
async exportData () {
this.exportLoading = true
let startTime, endTime
if (this.collectTime) {
startTime = this.collectTime[0] / 1000
endTime = this.collectTime[1] / 1000 + 86399
}
try {
const data = await ExportXXXReportList({
Id: this.id || 0,
StartTime: startTime || 0,
EndTime: endTime || 0,
Type: this.type || 0,
})
var raw = window.atob(data)
var uInt8Array = new Uint8Array(data.length)
for (var i = 0; i < raw.length; i++) {
uInt8Array[i] = raw.charCodeAt(i)
}
const url = window.URL.createObjectURL(new Blob([ uInt8Array ], { type: 'application/vnd.ms-excel' }))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', 'xxxx报表.xlsx')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
} catch (error) {
this.exportLoading = false
}
this.exportLoading = false
},
},
}
</script> <style lang="scss">
</style>

3、分析问题

这里有几个可能的原因和建议来解决这个问题:

①数据问题:首先确保你的数据源是正确的。检查你的表格数据是否有任何错误或遗漏。

②嵌套表格的渲染时机:如果你的嵌套表格(子表格)是在父表格的某一行展开时才渲染的,那么你需要确保子表格的数据在正确的时机进行加载。如果数据加载过早,可能会导致异常。

③弹窗的v-if与v-show:如果你使用了v-if来控制弹窗的显示与隐藏,那么每次弹窗打开都会重新渲染弹窗内的内容。这可能会导致表格的重新初始化,使用v-show可能会避免这个问题。但需要注意的是,v-show只是在视觉上隐藏元素,元素仍然会被渲染。

④表格的key:如前面所说,Vue使用key来追踪节点的身份。如果在嵌套表格的场景中,你使用了相同的key,可能会导致身份识别混乱。确保每个表格都有一个独特的key。

⑤样式冲突:确保没有其他样式影响到表格或弹窗的正常显示。特别是当你使用了自定义样式或与Element UI样式冲突的其他UI库时。

⑥组件版本:确保你使用的Element UI是最新的版本。旧版本可能存在已知的错误,而在新版本中可能已经被修复。

4、解决问题

下面我从表格的key角度解决下问题

1)尝试给每个弹窗的el-table加个key -- 未解决数据错乱的问题

示例代码如下:

<el-table
:key="Id"
stripe
style="width: 100%"
v-loading="loading"
row-key="Id"
height="300" max-height="300">
</el-table>

2)尝试给每个弹窗的el-table加个唯一的key -- 解决数据错乱的问题

示例代码如下:

<el-table
:key="Id"
stripe
style="width: 100%"
v-loading="loading"
row-key="Id"
height="300" max-height="300">
</el-table>

虽然此种方法解决了我们的问题,但是考虑到每次打开弹窗都会生成随机数存在一定风险性,具体分析如下:

随机数改变了每次渲染时的key值,打破了Vue的节点身份追踪机制。

    在这种情况下,由于每次渲染都有一个新的随机数作为key,Vue会将该组件视为全新的节点,从而重新渲染。这样可以避免由于身份追踪导致的问题,例如在嵌套表格场景中可能出现的报错。

    然而,需要注意的是,使用随机数作为key并不是一个推荐的做法。因为key的主要作用是帮助Vue高效地识别和追踪节点的身份,以便进行差异化更新。随机数作为key会破坏这一机制,可能导致性能下降和潜在的问题。

    因此,尽管使用随机数作为key可以解决某些情况下的报错,但并不是一个优雅的解决方案。更好的方式是仔细排查问题,找到导致报错的根本原因,并采取相应的措施进行修复。如果实在无法找到其他解决方案,再考虑使用随机数作为临时方案。但在长期开发中,仍然建议寻求更合适、更稳定的解决方案。

3)尝试给每个弹窗的el-table加个唯一的key(固定不是随机数) -- 解决数据错乱的问题(推荐)

示例代码如下:

<el-table
:key="generateKey(scheduledDataDownloadInfo)"
stripe
header-row-class-name="bos_table_header"
style="width: 100%"
v-loading="loading"
row-key="Id"
height="300" max-height="650"
:data="scheduledDataDownloadInfo">
</el-table>

在methods中添加方法

// 生成唯一的key,可以根据具体情况定义
generateKey (data) {
const uniqueIdentifier = data.map(item => item.Id).join('_')
return `table_${uniqueIdentifier}`
},

至此,更合适、更稳定的解决方案完成,我们开头提到的问题得以解决。有更好办法或者见解的同学欢迎评论区留言,互相学习。

若本文有帮助到阅读本文的同学,欢迎点赞、关注、收藏,互相学习交流

el-table 多表格弹窗嵌套数据显示异常错乱问题的更多相关文章

  1. 基于CSS属性display:table的表格布局的使用

    项目改造中遇到DIV+CSS实现的table,新需求需要在表格使用单元格合并,网上调查返现CSS display:table实现的table表格,没有单元格的属性和样式,经过一番思考,曲折现实了单元格 ...

  2. element-ui中table表头表格错误问题解决

    我用的是element-ui v1.4.3 在iframe关闭和切换导航会引起有table的表格错位,解决办法: handleAdminNavTab: function(tab) { var admi ...

  3. <HTML>在一个表格内嵌套另一个表格时,如何居中?

    在一个表格内嵌套另一个表格时,如何居中? 假设大表格为: <table id="tableRow"> <tr> <th>City</th& ...

  4. bootstarp-table表格中嵌套多个BUTON按钮实现

    bootstarp-table表格中嵌套多个BUTON按钮实现   有时我们需要在bootsharp-table表格中嵌套多个按钮,来实现不同的功能,大概界面如下:   实现功能如下: 1:构建表格 ...

  5. LayUI之table数据表格获取行、行高亮等相关操作

    前言 目前LayUI数据表格既美观有不乏一些实用功能.基本上表格应有的操作已经具备,LayUI作者[贤心]肯定是煞费苦心去优化,此处致敬.但是实话实话,如果单纯那数据表格功能来说,EasUI的数据表格 ...

  6. layui table数据表格reload where参数保留问题

    layui table数据表格reload where参数保留问题 在使用layui过程中多多少少会遇到些问题 table reload 有个坑:reload时where参数会保留上次的参数,如果用 ...

  7. 项目总结17-使用layui table分页表格

    项目总结17-使用layui table分页表格总结 前言 在项目中,需要用到分页的表格来展示数据,发现layui的分页表格,是一个很好的选择:本文介绍layui table分页表格的前后端简单使用 ...

  8. table设置表格有滚动条

    table 设置表格有滚动条. 少说多做,代码中有注释: <!DOCTYPE HTML> <html> <head> <meta http-equiv=&qu ...

  9. table(表格)中的标签和属性

    1.表格由 <table> 标签来定义.行( <tr> ),单元格(<td> ) 字母 td 指表格数据(table data),即数据单元格的内容.数据单元格可以 ...

  10. CSS Table(表格)

    CSS Table(表格) 一.表格边框 border 指定CSS表格边框,使用border属性. 下面的例子指定了一个表格的Th和TD元素的黑色边框: table, th, td { border: ...

随机推荐

  1. 文心一言 VS 讯飞星火 VS chatgpt (64)-- 算法导论6.5 3题

    文心一言 VS 讯飞星火 VS chatgpt (64)-- 算法导论6.5 3题 三.要求用最小堆实现最小优先队列,请写出 HEAP-MINIMUM.HEAP-EXTRACT-MIN.HEAP DE ...

  2. Redis从入门到放弃(3):发布与订阅

    1.介绍 Redis是一个快速.开源的内存数据库,支持多种数据结构,如字符串.哈希.列表.集合.有序集合等.除了基本的数据存储和检索功能外,Redis还提供了许多高级功能,其中之一就是发布订阅(Pub ...

  3. 三个编程思想:面向对象编程、面向接口编程、面向过程编程【概念解析系列_1】【C# 基础】

    〇.前言 对于 .Net 中的编程思想还是十分重要的,也是编码出高效的程序的基础! 在使用之前了解其本质,那么用起来就游刃有余.下面来简单对比下三个编程思想,看下它们都是什么,它们之间又有什么关系. ...

  4. 解决npm install 报错 'proxy' config is set properly. See: 'npm help config'

    输入以下命令 npm config set proxy null npm config set https-proxy null 之后重新安装即可 文章参考 https://blog.csdn.net ...

  5. deepin install mariadb

    输入指令: sudo apt-get install mariadb-server mariadb-client

  6. C#.NET 国密SM4对称加解密 与JAVA互通 ver:20230731

    C#.NET 国密SM4对称加解密 与JAVA互通 ver:20230731 .NET 环境:.NET6 控制台程序(.net core). JAVA 环境:JAVA8,带maven 的JAVA控制台 ...

  7. OpenSSH版本升级漏洞修复问题

    Hi, I'm @Merbelue 大家好,这篇为大家介绍二进制方式对OpenSSH版本升级,在生产环境中可用于解决版本升级.漏洞修复等. @ 目录 1.环境 2.安装telnet 2.1.检查是否安 ...

  8. stencilJs学习之构建 Drawer 组件

    前言 在之前的学习中,我们已经掌握了 stencilJs 中的一些核心概念和基础知识,如装饰器 Prop.State.Event.Listen.Method.Component 以及生命周期方法.这些 ...

  9. 谈一谈电商api的未来

    随着互联网的飞速发展,电商行业已经成为了现代消费的主流模式.在电商平台上,商品的交易.物流.支付等环节都需要使用API(Application Programming Interface)接口来实现信 ...

  10. IDEFICS 简介: 最先进视觉语言模型的开源复现

    引言 Code Llama 是为代码类任务而生的一组最先进的.开放的 Llama 2 模型,我们很高兴能将其集成入 Hugging Face 生态系统!Code Llama 使用与 Llama 2 相 ...