JSON生成HTML页面时SVG元素无法显示的技术求助
动态生成SVG不显示的问题解决
我通过JavaScript从JSON结构生成HTML页面,所有元素都能正常渲染,唯独SVG元素虽然已存在于DOM中,但浏览器无法显示。奇怪的是,在开发者工具的Inspector里手动给SVG元素后加个<br>标签,SVG就立刻显示出来了。
我尝试过用createElementNS创建SVG元素,但只有当JSON中只包含SVG元素时有效,一旦加入img等其他元素,SVG又无法显示。相关代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <svg height="70" width="150"> <polygon points="2,10 50,7 139,32 66,51"></polygon> </svg> <div class="container"> </div> </body> <script> function renderHtmlElements(data) { const element = document.createElement(data.tag); if (data.attributes) { Object.keys(data.attributes).forEach(key => { element.setAttribute(key, data.attributes[key]); }); } if (data.children) { data.children.forEach(childData => { const childElement = renderHtmlElements(childData); element.appendChild(childElement); }); } if (data.textNode) { element.appendChild(document.createTextNode(data.textNode)); } return element; } // parent to insert the HTML const container = document.querySelector(".container"); // data for the HTML in a JSON object const htmlData = { "tag": "div", "attributes": { "id": "L1", "class": "Labels" }, "children": [ { "tag": "img", "attributes": { "class": "", "src": "", "width": "160", "height": "100" }, "children": [] }, { "tag": "div", "attributes": {}, "children": [ { "tag": "svg", "attributes": { "width": "150", "height": "70" }, "children": [ { "tag": "polygon", "attributes": { "points": "2,10 50,7 139,32 66,51" }, "children": [] } ] } ] } ] } // Create the HTML element from the JSON data and append it to the container const htmlElement = renderHtmlElements(htmlData); container.appendChild(htmlElement); </script> </html>
我还试过下面这段代码,但依然无法解决问题:
function renderHtmlElements(data) { let element; if (data.tag === "svg") { element = document.createElementNS("http://www.w3.org/2000/svg", data.tag); } else { element = document.createElement(data.tag); } if (data.attributes) { Object.keys(data.attributes).forEach(key => { if (data.tag === "svg") { element.setAttributeNS("http://www.w3.org/2000/svg", key, data.attributes[key]); } else { element.setAttribute(key, data.attributes[key]); } }); } if (data.children) { data.children.forEach(childData => { const childElement = renderHtmlElements(childData); element.appendChild(childElement); }); } if (data.textNode) { element.appendChild(document.createTextNode(data.textNode)); } return element; }
问题原因
问题出在SVG的所有子元素(比如polygon、path等)也需要使用SVG命名空间创建。之前的代码只给<svg>标签本身用了createElementNS,但它的子元素还是用普通的createElement创建,导致浏览器无法正确识别这些SVG内部元素,最终SVG无法渲染。
解决方案
修改renderHtmlElements函数,判断当前元素是否属于SVG命名空间(包括SVG本身和它的所有子元素),如果是,就用createElementNS创建,命名空间为http://www.w3.org/2000/svg。
修正后的代码如下:
function renderHtmlElements(data) { // SVG标准命名空间 const SVG_NS = "http://www.w3.org/2000/svg"; // 列出所有需要用SVG命名空间创建的元素,可根据需求扩展 const svgElements = ["svg", "polygon", "path", "circle", "rect", "line", "ellipse", "text"]; let element; if (svgElements.includes(data.tag)) { element = document.createElementNS(SVG_NS, data.tag); } else { element = document.createElement(data.tag); } if (data.attributes) { Object.keys(data.attributes).forEach(key => { // SVG普通属性直接用setAttribute即可,无需命名空间(特殊属性如xlink:href除外) element.setAttribute(key, data.attributes[key]); }); } if (data.children) { data.children.forEach(childData => { const childElement = renderHtmlElements(childData); element.appendChild(childElement); }); } if (data.textNode) { element.appendChild(document.createTextNode(data.textNode)); } return element; }
说明
- 首先定义SVG标准命名空间,然后维护一个需要使用该命名空间的元素列表,覆盖SVG本身和常用内部元素;
- SVG元素及其子元素都通过
createElementNS创建,确保浏览器能正确识别SVG结构; - 普通属性直接用
setAttribute设置即可,只有带命名空间的特殊属性(如xlink:href)才需要使用setAttributeNS。
内容的提问来源于stack exchange,提问作者xodes
相关产品推荐
相关产品推荐

