el-tabs 页签中表格组件宽度闪动问题解决方案

0 阅读2分钟

背景

项目中有一个表格组件用在页签组件下,在页签切换时表格的宽度会出现跳动,具体表现就是表格会“闪”一下,示例代码如下:

<el-tabs type="card" v-model="activeName">
    <el-tab-pane label="系统配置" name="system"><systemData /></el-tab-pane>
    <el-tab-pane label="流程管理" name="flow"><flow /></el-tab-pane>
</el-tabs>

问题定位

  1. 通过观察表格的元素,可以看到表格的宽度发生了变化,为了进一步定位触发宽度改变的代码位置,采用 dom 属性断点来观察代码执行

image.png

  1. 执行页签切换动作,复现问题,观察代码执行状态和运行堆栈

image.png

image.png

  1. 通过断点可以得到以下几个关键信息点:
    1. 页签切换时,触发了 resizeListener ,进而触发宽度计算函数
    2. resizeListener 触发 doLayout 的逻辑是宽度或高度发生变化
    3. 由上述分析可以得到问题的根本原因是页签切换时 el-panel 被设置为 display:none 使得容器宽度坍缩为 “0” ,触发了 resizeListener,页签切换回来时宽度恢复,这里再次被触发,所以宽度会在切换的瞬间发生跳动

解决方案

通过上述分析,我们可以知道根本原因就是页签切换时容器的宽度和高度坍缩为“0”导致的问题,从源码中我们也可以看到高度的判断有一个 !this.height 的判断,但是宽度没有加上这个判断,我的解决方案是在组件的 mounted 钩子中加一段代码重写 el-table 内部的 resizeListener 方法解决这个BUG,示例代码如下:

<template>
    <el-table ref="elTable"></el-table>
</template>
<script>
export default {
    mounted() {
        // 解决 el-table 在容器宽度为0时,宽度闪烁的问题
        const _tableResizeListener = this.$refs.eltable.resizeListener
        this.$refs.eltable.resizeListener = function () {
          // 当元素的宽度和高度不为 0 时才触发 resize
          if (!this.$el || !this.$el.offsetWidth || !this.$el.offsetHeight) {
            return
          }
          _tableResizeListener.call(this);
        }
        this.$refs.eltable.unbindEvents()
        this.$refs.eltable.bindEvents()
    }
}
</script>

总结

这个问题的排查其实还比较顺利,因为一开始断点后基本就定位到问题了,后面就是针对性解决问题,我这里没有直接改 elment-ui 的源码一个原因是官方已经停止维护,提 PR 也无济于事,在代码中通过这种打补丁的方式来解决问题是最快捷也最有效的方式,同时也不破坏原有的组件框架。