昨天下午,同事再写新项目页面时发现了一个问题,由于这个项目的框架是我搭建的,这个问题大概是折叠、打开二级菜单时主视图的 Echart 图表显示异常,宽度没有自适应。
问题分析
在听他描述时,我第一想法是检查他的代码中是否在 resize
事件中调用了 chartInstance.resize
方法,因为 Echart 图表的宽度是根据容器的宽度来自适应的,所以在页面宽度发生变化时,需要调用 chartInstance.resize
方法来重新计算图表的宽度。
但是发现他调用了这个方法,但是 Echart 图表却没有任何变化,我就想到是否是因为切换二级菜单时,并没有触发 resize
事件,因为页面整体的宽度并没有发生改变,只是二级菜单的宽度发生了改变,所以我就使用 new Event('resize')
来手动触发 resize
事件;
const onChangeCollapse = () => {
const resizeEvent = new Event('resize');
window.dispatchEvent(resizeEvent);
// ... 其他逻辑代码
};
这时切换二级菜单是否折叠时 chartInstance.resize
方法正常被调用了,图表的宽度也重新计算了,但是图表宽度确仍然异常,具体表现是,在二级菜单折叠时 Echart 图表却渲染的宽度较短,在二级菜单打开时 Echart 图表却渲染的宽度较长,超出屏幕范围。这一奇怪的现象起初令我很是疑惑。
然后我将 chartInstance.resize
调用放入 setTimeout
中并设置 1s 的延迟执行,发现一切都正常了,这时也打消了我刚刚的疑惑。
刚刚这一异常渲染表现是因为容器的宽度改变并不是实时的,而是有延迟,所以导致每次 chartInstance.resize
调用时都是以前一次的宽度进行渲染的。
既然找到了原因,问题就很容易解决了,只需要将 chartInstance.resize
放入 setTimeout
并以一个合理的延迟时间运行即可,我控制二级菜单折叠展开的动画持续时间是 0.3s,因此将setTimeout
第二个参数设置为 300,就解决了这个问题。
完美解决方案
在记录这个问题时突然想到,这样修改的话需要在每个 chartInstance.resize
都需要放入延时器中执行,有些麻烦,且未来如果更改了控制二级菜单折叠展开的动画持续时间就需要在每个页面都更改,不太方便,因此可以将手动触发 resize
事件放入setTimeout
中执行,那么动画已经结束,然后再触发 resize 事件,页面中接收到 resize
事件时对应的容器宽度也已经正常改变完成了。
const DEALY = 0.3;
const onChangeCollapse = () => {
setTimeout(() => {
const resizeEvent = new Event('resize');
window.dispatchEvent(resizeEvent);
// ... 其他逻辑代码
}, DEALY * 100);
};