ApexCharts切换页面报svg height为NaN错误,求最优解决方案
ApexCharts DOM移除后NaN高度报错的问题分析与解决
问题本质
这属于ApexCharts对DOM元素被意外移除的场景处理不到位,说它是Bug也不为过——当Knockout的data-bind="if"把图表容器从DOM里删掉时,ApexCharts的实例没察觉到容器已经不存在,还会在redrawOnParentResize触发时尝试读取容器尺寸,自然算出NaN的height值。
更靠谱的解决办法
1. 借Knockout的销毁钩子主动销毁图表
既然用了Knockout,直接在容器被移除前销毁图表实例才是最根本的解决办法,无需额外添加ResizeObserver:
- 编写自定义Knockout绑定,将图表的创建与销毁绑定到元素生命周期
- 示例代码:
// 自定义Knockout绑定 ko.bindingHandlers.apexChart = { init: function(element, valueAccessor) { const opts = ko.unwrap(valueAccessor()); const chart = new ApexCharts(element, opts); chart.render(); // 元素被销毁时自动销毁图表 ko.utils.domNodeDisposal.addDisposeCallback(element, () => { chart.destroy(); }); } }; // 模板中使用 <div data-bind="if: showChart, apexChart: myChartOpts"></div>
这样容器被Knockout移除时,图表会同步销毁,不会残留resize监听引发错误。
2. 优化你的ResizeObserver方案
要是不想修改绑定逻辑,可以优化现有ResizeObserver实现,避免无效监听:
const chartEl = document.getElementById('myChart'); const chart = new ApexCharts(chartEl, chartOpts); chart.render(); const observer = new ResizeObserver(entries => { const { height } = entries[0].contentRect; if (height === 0 && chart) { chart.destroy(); observer.disconnect(); // 销毁图表后停止监听,节省资源 } }); observer.observe(chartEl);
相比原方案增加了断开监听的步骤,避免不必要的性能消耗。
3. 全局打个临时补丁
要是不想改动业务代码,可以给ApexCharts的redraw方法添加容器存在性校验:
// 重写redraw方法,增加容器存在性检查 const originalRedraw = ApexCharts.prototype.redraw; ApexCharts.prototype.redraw = function() { // 检查容器是否仍在DOM中 if (!this.el || !document.body.contains(this.el)) return; originalRedraw.call(this); };
这个方法适合全局统一处理,但注意升级ApexCharts版本时可能需要重新适配。
关于Bug的确认
社区中已有不少开发者反馈过类似问题,ApexCharts后续版本(比如v3.50及以上)已优化了DOM销毁后的监听清理逻辑,v3.45.1确实存在这个问题。如果可以升级版本,直接更新到较新的稳定版大概率能解决该问题。
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

