• vue keepalive情况下切换页面的tab并改变宽高以后发现echarts内容变成空白


    vue中使用keep-alive缓存后处于disactivated状态的echarts表格自适应功能(resize)失效的解决办法

    在vue开发中的时候,使用keep-alive监听的页面,echart或者地图相关的模块,测试提出了一个bug,页面偶现空白。

    经过排查发现重现步骤如下:

      离开当前页面以后,再其他tab页面切换了窗口大小,再回到原页面,发现echart不显示了,再重新改变一下窗口大小,就又恢复正常

    原因:  

      之前为了实现echarts的自适应,添加了一个监听器监测window窗口是否发生变化,如果变化了就执行echarts自带的resize方法来改变一下echarts的大小,并且将这个方法习惯性地写在了生成echarts的方法中。但是,我们使用了keep-alive,进行缓存后情况就有点不一样了。我们绘制Echarts的方法是写在mounted生命周期中的,而切换页面并会不会进入destroyed生命周期,而是进入disactivated生命周期,这使得mounted中的函数还是激活状态,我们之前添加的监听器仍然在工作,但是但是但是,之前缓存页面的dom没了,打印出来的高度为0,我们的eventListener监听到了别人家的dom变了,高度为0,所以图表也为0。

      然后,当切换回已缓存的页面时,bug就来了。echarts消失了。

      然后你再改变一下宽口大小,echarts又回来了。。。

      这是因为你之前你改变dom的时候,echarts重画失败了,可是你切回来的时候,dom虽然相对于你切出去之前可能变了,但是对于监听器来说,他只关注于当前dom大小是否改变了。所以刚切回来的时候echarts的resize方法不会被激活。而只要稍稍改变一下dom的大小,就可以激活resize方法。

    解决方案如下:

      方法一:引入element-resize-detector插件进行处理

    <template>
      <div ref="chart"></div>
    </template>
    <script>
    import elementResizeDetector from "element-resize-detector";
    import * as echarts from "echarts/core";
    import { LineChart, BarChart, PieChart, GraphChart, LinesChart} from "echarts/charts";
    import { GridComponent, SingleAxisComponent, TooltipComponent, AxisPointerComponent, TitleComponent, LegendComponent } from "echarts/components";
    import { CanvasRenderer } from "echarts/renderers";
    
    echarts.use([
      TitleComponent,
      TooltipComponent,
      LegendComponent,
      SingleAxisComponent,
      GridComponent,
      AxisPointerComponent,
      BarChart,
      LineChart,
      PieChart,
      GraphChart,
      LinesChart,
      CanvasRenderer
    ]);
    
    export default {
      name: "viChart",
      props: {
        options: {
          type: Object,
          required: true
        },
        isClear: {
          type: Boolean,
          default: true
        }
      },
      data() {
        return {
          myChart: null,
          erd: null,
        };
      },
      beforeDestroy() {
        this.dispose();
      },
      methods: {
        watchOptions() {
          this.$watch("options", this.setOption, { deep: true });
        },
        init() {
          this.myChart = echarts.init(this.$refs.chart);
          this.setOption();
        },
        resize() {
          if (!this.myChart) return;
          this.myChart.resize();
        },
        setOption() {
          if (!this.myChart || Object.keys(this.options).length === 0) return;
          if (this.isClear) {
            this.myChart.clear();
          }
          this.myChart.setOption(this.options);
          // this.resize();
        },
        dispose() {
          if (!this.myChart) return;
          this.myChart.dispose();
        }
      },
      mounted() {
        this.init();
        this.watchOptions();
        this.erd = elementResizeDetector();
        this.erd.listenTo(this.$refs.chart, this.resize);
      },
      beforeDestroy() {
        this.erd.removeListener(this.$refs.chart);
      }
    };
    </script>

      方法二:使用指令方法,监听DOM元素宽度变化。该方法是定时循环调用时间监听,判断宽高变化,比较消耗资源,不建议。

    <template>
      <div ref="chart" v-resize="resize"></div>
    </template>
    <script>
    import * as echarts from "echarts/core";
    import { LineChart, BarChart, PieChart, GraphChart, LinesChart} from "echarts/charts";
    import { GridComponent, SingleAxisComponent, TooltipComponent, AxisPointerComponent, TitleComponent, LegendComponent } from "echarts/components";
    import { CanvasRenderer } from "echarts/renderers";
    
    echarts.use([
      TitleComponent,
      TooltipComponent,
      LegendComponent,
      SingleAxisComponent,
      GridComponent,
      AxisPointerComponent,
      BarChart,
      LineChart,
      PieChart,
      GraphChart,
      LinesChart,
      CanvasRenderer
    ]);
    
    export default {
      name: "viChart",
      props: {
        options: {
          type: Object,
          required: true
        },
        isClear: {
          type: Boolean,
          default: true
        }
      },
      data() {
        return {
          myChart: null
        };
      },
      mounted() {
        this.init();
        this.watchOptions();
      },
      beforeDestroy() {
        this.unbind();
        this.dispose();
      },
      methods: {
        watchOptions() {
          this.$watch("options", this.setOption, { deep: true });
        },
        init() {
          this.myChart = echarts.init(this.$refs.chart);
          this.setOption();
        },
        unbind() {
          window.removeEventListener("resize", this.resize);
        },
        resize() {
          if (!this.myChart) return;
          this.myChart.resize();
        },
        setOption() {
          if (!this.myChart || Object.keys(this.options).length === 0) return;
          if (this.isClear) {
            this.myChart.clear();
          }
          this.myChart.setOption(this.options);
        },
        dispose() {
          if (!this.myChart) return;
          this.myChart.dispose();
        }
      },
      directives: {  // 使用局部注册指令的方式。主要处理keep-alive情况下,切换到其他tab情况下,再切回原页面,echart不见了
        resize: { // 指令的名称
          bind(el, binding) { // el为绑定的元素,binding为绑定给指令的对象
            let width = ""; let height = "";
            function isReize() {
              const style = document.defaultView.getComputedStyle(el);  // 获取对象的css样式,返回的是一个CSS样式对象
              if (width !== style.width || height !== style.height) {
                binding.value();  // 关键
              }
              width = style.width;
              height = style.height;
            }
            el.__vueSetInterval__ = setInterval(isReize, 300);
          },
          unbind(el) {
            clearInterval(el.__vueSetInterval__);
          }
        }
      },
    };
    </script>
    

      

     参考文档:

    https://blog.csdn.net/kiwon1993/article/details/102638808

    https://blog.csdn.net/csl125/article/details/115075643

  • 相关阅读:
    到达波密
    福建
    到达拉萨
    樟木半天游
    修改控制寄存器GPBCON
    WINCE实现屏幕旋转的方法
    6410主频
    如何解决触摸屏抖动问题
    视频格式D1
    安家了
  • 原文地址:https://www.cnblogs.com/luoxuemei/p/16145645.html
Copyright © 2020-2023  润新知