• echarts遇到resize失效问题


    1、问题描述

    在前端页面中,echarts图形在容器div发生变化时,能够自适应调整大小。注意这里说的是容器div发生变化时,不是浏览器窗口发生变化的时候。实际场景是,在点击菜单的按钮,导致了echarts容器div发生了变化,但echarts没有resize(),导致很丑。

    2、解决过程

    2.1 项目的现状

    在窗口发生变化的时候,触发了resize事件,echarts容器发生变化,调用echarts的resize函数,做了自适应调整。代码实现如下(普通场景木问题,部分场景会造成内存泄露,取决于你的框架代码的实现):

     myChart.setOption(option);
     window.addEventListener("resize", function () {
     	 myChart.resize();
    });
    

    如果事件绑定在window上,这些变量生命周期就会随着页签一直存在,一直在内存当中。如果不停的重新加载和刷新(子页面),就会造成内存泄露。正确姿势如下:

         //在初始化页面的时候注册一下
     function resizeEcharts(){
     	//$box.find('[data-toggle="echarts"]') 获取echarts的容器
         $box.find('[data-toggle="echarts"]').each(function(){
             var element = $(this)[0];
             echarts. getInstanceByDom(element).resize();
         })
     }
     window.addEventListener("resize",resizeEcharts);
    

    2.2 div自适应解决方案

    解决思路:

    1. 侦听div的变化,触发resize
    2. 由于按钮触发echarts的容器div的变化,按钮绑定触发事件

    2.2.1 div的变化,触发resize

    实现一

    (function ($, window, undefined) {
        var elems = $([]),//空的数组
            jq_resize = $.resize = $.extend($.resize, {}),
            timeout_id,
            str_setTimeout = 'setTimeout',
            str_resize = 'resize',
            str_data = str_resize + '-special-event',
            str_delay = 'delay',
            str_throttle = 'throttleWindow';
        jq_resize[str_delay] = 250;
        jq_resize[str_throttle] = true;
        $.event.special[str_resize] = {
            setup: function () {
                if (!jq_resize[str_throttle] && this[str_setTimeout]) {
                    return false;
                }
                var elem = $(this);
                elems = elems.add(elem);
                $.data(this, str_data, {
                    w: elem.width(),
                    h: elem.height()
                });
                if (elems.length === 1) {
                    loopy();
                }
            },
            teardown: function () {
                if (!jq_resize[str_throttle] && this[str_setTimeout]) {
                    return false;
                }
                var elem = $(this);
                elems = elems.not(elem);
                elem.removeData(str_data);
                if (!elems.length) {
                    clearTimeout(timeout_id);
                }
            },
            add: function (handleObj) {
                if (!jq_resize[str_throttle] && this[str_setTimeout]) {
                    return false;
                }
                var old_handler;
     
                function new_handler(e, w, h) {
                    var elem = $(this),
                        data = $.data(this, str_data);
                    data.w = w !== undefined ? w : elem.width();
                    data.h = h !== undefined ? h : elem.height();
                    old_handler.apply(this, arguments);
                }
     
                if ($.isFunction(handleObj)) {
                    old_handler = handleObj;
                    return new_handler;
                } else {
                    old_handler = handleObj.handler;
                    handleObj.handler = new_handler;
                }
            }
        };
     
        function loopy() {
            timeout_id = window[str_setTimeout](function () {
                elems.each(function () {
                    var elem = $(this),
                        width = elem.width(),
                        height = elem.height(),
                        data = $.data(this, str_data);
                    if (width !== data.w || height !== data.h) {
                        elem.trigger(str_resize, [data.w = width, data.h = height]);
    					//错误代码(直接在这边)  《《《《《《《《《《《《《《代码1》》》》》》》》》》》》》》
                    }
                });
                loopy();
            }, jq_resize[str_delay]);
        }
    })(jQuery, this);
    //监听div大小变化事件
    $("div").resize(function(){
        console.log("触发了....");
    })
    
    

    这么一大段代码,看着有点稀里糊涂的,看着网上的文章,说侦听div的变化,当div的变化,触发resize事件。在本地实验可以,的确可以侦听到。如果直接在《代码1》写触发代码,会一直循环,还无法侦听指定div的变化。对jquery的事件绑定,这部分知识欠缺,读这段代码,有点吃力。

    实现二(未验证):

    2.2.2 触发事件

    触发事件,思路比较简单,实现也比较容易,但是容易掉坑里面。

    2.2.2.1 探索过程

    对定的元素绑定点击事件,触发resise事件,代码如下:

    //b被点击的按钮
    var btn1=$("#hide-menu");
    btn1.on("click",function(){
    	var event= new Event("resize");
    	window.dispatchEvent(event);
    })
    
    //echarts的容器
    window.addEventListener("resize",function(){
    	mychart.resize();
    })
    

    这个过程简单吧,只是一个触发事件过程和一个监听事件过程。正常场景下,应该可以完美的解决这个问题。但是在项目框架中,就卡住了,虽然运行了,没有达到预期的效果,一度让我有点奔溃了。然后就陷入了一个怪坑,echarts的resize失效。网上找各种这个问题的解决方案,然并卵毫无作用。

    说法一:“宽度100%,高度vh,就可以解决了”ECharts的resize失效原因以及使用方法

    说法二:“$(“#vid”).css("height",$(vid).height);宽度一样”

    说法三:“特定版本的问题”

    说法四:“样式的影响”

    ......

    2.2.2.2 分析过程
    1. 剥离框架,写一个小程序,验证方法的可行性(实际可行)
    2. 添加样式,依旧可行
    3. 添加打印,对比resize起作用前后的变化。
      1. div容器的宽和高
      2. mycharts的宽和高(echarts对象的方法获取)
      3. 在resize1起作用前,上面两者是不一致的
    4. 回到框架代码,发现触发事件的时候,一直处于一致状态。
      1. 通过我的好眼力,发现resize事件处理领先于div的宽高调整
    5. 进一步发下,这个按钮绑定了其他事件,导致了先resize,然后再调整宽和高。
    6. 在之前绑定的事件的回调函数中,触发新的事件,保证先后顺序。
    2.2.2.3 代码实现过程

    1、正确的实现的姿势

    var btn1=$("#hide-menu");
    btn1.on("click",function(){
       //省略
           $navtab
           .stop()
           .animate(opts, 'fast',function(){
           	    var myEvent = new Event("echartDivChange");
    		    window.dispatchEvent(myEvent);
           })
    })
    //echarts的容器
    window.addEventListener("echartDivChange",function(){
    	mychart.resize();
    })
    

    2、trigger 触发事件,又掉入另外一个坑里面(错误示范)

    var btn1=$("#hide-menu");
    btn1.on("click",function(){
    	//........
           $navtab
           .stop()
           .animate(opts, 'fast',function(){        	  
    			 $(window).trigger("echartDivChange");//方式1	
     			//$(document).trigger("echartDivChange");//方式2
    			//$("#123").trigger("echartDivChange");//方式3
           })
    })
    //echarts的容器(错误示范)
    $("#mycharts").on("echartDivChange",function(){
    	mychart.resize();
    })
    

    看框架源码,有的事件是交叉触发和捕获,这种方式应该是错误的。在这种方式中无法捕获,一定要选择对应方式。 例如,$(window)需要用 $(window)去捕获。这里面还有知识点,事件的冒泡机制,理解这个,对事件触发和捕获才能合理利用。

    3、知识点提炼

    • resize事件
    • on
    • 自定义event触发和捕获
    • 冒泡机制
    • $.event.special(待学习)

    4、总结

    在定位这个问题过程中,还是花了很长时间的。在定位过程,掉进坑里面,无法爬出来。原因分为两个方面,一:知识体系不够完善;二:遇到坑的分析解决的方式有问题。

    4.1 知识体系不够完善

    只能带着积累,学习新的东西。

    4.2 遇到问题解决方式

    1. 怀疑开源组件的问题

    这个可以将开源组件剥离当前框架,写个小程序直接验证。直接来个demo,这个有时候还是不习惯,或者有点反应慢。

    1. 遇到问题的搜寻顺序
    • 搜索,要是有明确的答案直接用
    • 官方论坛
    • 再搜索
    1. 控制变量法

    不确定问题原因的可以验证单个因素的正确性,然后再组合验证。发现是不是组合了才导致问题发生了。

  • 相关阅读:
    Struts2(十六)Json
    Struts2(十五)实现文件上传
    Struts2(十四)拦截器实现权限管理
    Eclipse下link方式安装插件
    Struts2(十三)国际化-internationalization
    Struts2(十二)使用验证框架验证数据较验
    Struts2(十一)OGNL标签三与Struts2标签
    Struts2(十)OGNL标签二与Struts2标签
    Struts2(九)OGNL标签一与Struts2标签
    Elasticsearch 分词器
  • 原文地址:https://www.cnblogs.com/meiguhuaxian/p/12935394.html
Copyright © 2020-2023  润新知