使用JS修改SVG图片文本时contentDocument不一致、修改偶发失效如何解决
问题根因
你遇到的contentDocument不一致、注入偶发失效的核心原因是 SVG通过object标签加载是异步行为:
- 你修改
data属性后,浏览器不会等待SVG资源加载、解析完成就会直接执行后续的打印、注入逻辑,此时拿到的contentDocument还是上一个已加载完成的旧SVG的内容,或者加载未完成时contentDocument为空。 - 你后续看到页面渲染出新SVG,是因为打印逻辑执行完后SVG才加载完成更新了
contentDocument,时间差导致你看到打印值和实际渲染值不一致,本质是执行时机错误导致的问题。
解决方案
方案1:监听load事件修复现有实现(改动最小)
仅需要调整逻辑顺序,在SVG加载完成的回调中执行注入操作即可,同时添加判空逻辑避免异常:
修改切换SVG的代码:
$('#third-select-card').on("change", function(e){ var link = selectChange(); var $svgObj = $("#item-svg-chart"); // 解绑之前绑定的load事件,避免重复触发 $svgObj.off('load'); // 绑定load回调:SVG加载、解析完成后才会执行 $svgObj.on('load', function() { var svgChart = this.contentDocument; console.log(svgChart); // 此处调用注入函数才是合法时机 injectSVG(你的params参数); }); // 最后修改data属性触发加载 $svgObj.attr('data', link); })
优化注入函数,增加异常兼容:
function injectSVG(params) { var svgObj = document.getElementById("item-svg-chart"); // 先判空,避免加载未完成时报错 if (!svgObj || !svgObj.contentDocument || !params) return; var svgChart = svgObj.contentDocument; var textEls = svgChart.querySelectorAll('text.text-inject'); for (var i = 0; i < textEls.length; i++) { if (params[i]) { textEls[i].textContent = params[i].toString().replace("*", "\xB0"); } } }
方案2:改用内联SVG(彻底规避异步问题)
如果SVG文件体积不大,直接把SVG代码嵌入到HTML中,不需要通过object标签加载,可直接操作DOM节点,没有异步和contentDocument相关问题:
HTML嵌入示例:
<div class="img-fluid"> <!-- 直接将SVG源码粘贴到此处,给svg标签加对应id --> <svg id="item-svg-chart" xmlns="http://www.w3.org/2000/svg" ...> <!-- 原有SVG内容 --> <text class="text-inject">原有文本</text> </svg> </div>
此时注入函数可简化为:
function injectSVG(params) { if (!params) return; var textEls = document.querySelectorAll('#item-svg-chart text.text-inject'); for (var i = 0; i < textEls.length; i++) { if (params[i]) { textEls[i].textContent = params[i].toString().replace("*", "\xB0"); } } }
切换SVG时可以动态请求SVG文本后替换#item-svg-chart的内容即可。
内容的提问来源于stack exchange,提问作者NghiaBt
相关产品推荐
相关产品推荐

