问题描述:
继上次写博客记录的el-table+el-dialog的bug之后--
elementui el-table中每行嵌套的el-dialog的scope取值bug_el-table 行嵌套_FC_oder的博客-优快云博客s
今天又遇到了类似的问题:在el-table-column中嵌套使用el-dialog时,出现了dialog内容加载卡顿的问题
问题代码:(偷懒直接贴了上篇博客的)
<el-table-column align="right">
<template slot-scope="scope">
<el-button
size="mini"
@click="handleEdit(scope.$index)"
>
<i class="el-icon-info"></i> 详细信息 {{ scope.$index }}
</el-button>
<el-dialog
:title="`详细信息${scope.$index}`"
:visible.sync="dialogVisible"
width="25%"
:append-to-body="true"
:lock-scroll="false"
>
{{ scope.$index }}
<el-scrollbar>
<div class="list-item">
<el-table :data="listDataCopy[scope.$index]">
<el-table-column
label="属性"
prop="ParaDesc">
</el-table-column>
<el-table-column
label="数值"
prop="ParaValue">
</el-table-column>
</el-table>
</div>
</el-scrollbar>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogVisible = false"
>知道了</el-button>
</span>
</el-dialog>
</template>
</el-table-column>
问题分析:
项目中dialog需要渲染的是每种原油的70多种属性的数据,el-table负责对多种原油的属性数据进行渲染,在点击详情后弹出dialog展示对应油种的属性数据。
项目一开始的方案是在页面mounted钩子中直接向后端请求页面中所有的数据。然后在测试详情按钮的时候发现了本篇文章所描述的问题。
一开始认为问题出在el-table中所需渲染的列表(从后端请求得到的)数据过大导致的问题,这边让后端做了数据分页后,发现问题没有得到明显改善。
因此这边想到的第二个方法是在点击详情后,给dialog中加个elementui的加载样式,等到dialog中的元素渲染完毕后再关闭加载样式。这边采用了动态增加加载样式的方式,获取到classname为el-scrollbar__wrap的元素列表。
setTimeout(async ()=>{
const elem = document.getElementsByClassName('el-scrollbar__wrap')
console.log(elem)
const loading = this.$loading({
lock: true,
target: elem[0],
spinner: 'el-icon-loading',
background: 'rgba(255, 255, 255, 0.5)'
});
let form = new FormData()
// 向后端请求对应id的原油数据
form.append('id', this.id)
const res = await this.SENDMESSAGE(form)
loading.close()
res.data.data.forEach((val,key)=>{
this.dialogData.push({
paraDesc: labelsAll[key],
paraValue: val
})
})
},200)
然而在测试时发现并没有出现期望的加载样式,并且打印出来的elem足足25个之多。
这边终于才恍然大悟,原来dialog重复渲染了多次,在点击某个详情按钮时,增加的加载样式并不一定是显示在最顶层的dialog上。也正因为重复渲染,在dialog中节点数量较多的时候,会造成明显的卡顿。
而一开始未能及时排查出重复渲染问题的原因是,虽然重复渲染了多次dialog,但每个dialog所绑定的开启事件和关闭事件是完全相同的,打开和关闭dialog过程中除了加载略卡,其他并无异样。
因此,最终的解决方案也很简单,将dialog提出到el-table之外即可。
随后,这里我也是抱着一定的好奇心稍微研究了一下el-table的源码。 其中,el-table-column的核心代码可以参考这篇博客:
可以看到,el-table底层的逻辑是将待渲染的列表遍历一遍,同时column内的template中所有的元素会被遍历渲染。也验证了我的猜想。
总结:
目前认为最优的解决方案是将写在column内的dialog抽出在外层div写。因为el-table底层的逻辑是将待渲染的列表遍历一遍,同时column内的template中所有的元素会被遍历渲染。如果dialog写在column内除了会发生上一篇文章提到的问题之外,还会因为渲染过多重复节点出现性能问题。
欸,感觉这个问题还挺基础的。第一次发文章碰到这个问题的时候急着赶项目进度,没有仔细分析问题背后的原因。今天再次碰到类似的问题了,才静下心来的进行分析。希望自己在学习的过程中能多多积累类似的追根溯源的经验与能力。