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自适应解决方案
解决思路:
- 侦听div的变化,触发resize
- 由于按钮触发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 分析过程
- 剥离框架,写一个小程序,验证方法的可行性(实际可行)
- 添加样式,依旧可行
- 添加打印,对比resize起作用前后的变化。
- div容器的宽和高
- mycharts的宽和高(echarts对象的方法获取)
- 在resize1起作用前,上面两者是不一致的
- 回到框架代码,发现触发事件的时候,一直处于一致状态。
- 通过我的好眼力,发现resize事件处理领先于div的宽高调整
- 进一步发下,这个按钮绑定了其他事件,导致了先resize,然后再调整宽和高。
- 在之前绑定的事件的回调函数中,触发新的事件,保证先后顺序。
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 遇到问题解决方式
- 怀疑开源组件的问题
这个可以将开源组件剥离当前框架,写个小程序直接验证。直接来个demo,这个有时候还是不习惯,或者有点反应慢。
- 遇到问题的搜寻顺序
- 搜索,要是有明确的答案直接用
- 官方论坛
- 再搜索
- 控制变量法
不确定问题原因的可以验证单个因素的正确性,然后再组合验证。发现是不是组合了才导致问题发生了。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
· 程序员转型AI:行业分析