JavaScript中SVG节点的简洁构造

时间:2013-10-14 12:54:00

标签: javascript dom svg

考虑下面的SVG块:

<defs>
  <radialGradient id="gradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
    <stop offset="0%" style="stop-color:#568f82;stop-opacity:1" />
    <stop offset="100%" style="stop-color:#568f82;stop-opacity:0" />
  </radialGradient>
</defs>

创建这些元素的相应JavaScript是:

var defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
var radialGradient = document.createElementNS('http://www.w3.org/2000/svg', 'marker');
radialGradient.id = 'gradient';
radialGradient.setAttribute('cx', '50%');
radialGradient.setAttribute('cy', '50%');
radialGradient.setAttribute('fx', '50%');
radialGradient.setAttribute('fy', '50%');
radialGradient.setAttribute('r', '50%');
var stop1 = document.createElementNS('http://www.w3.org/2000/svg', 'path');
stop1.setAttribute('offset', '0%');
stop1.setAttribute('style', 'stop-color:#568f82;stop-opacity:1');
radialGradient.appendChild(stop1);
var stop2 = document.createElementNS('http://www.w3.org/2000/svg', 'path');
stop2.setAttribute('offset', '100%');
stop2.setAttribute('style', 'stop-color:#568f82;stop-opacity:0');
radialGradient.appendChild(stop2);
defs.appendChild(radialGradient);
this.svgElement.appendChild(defs);

有没有办法在JavaScript中内联使用XML标记?我尝试了类似以下的东西,但没有任何运气:

var defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
defs.innerHTML = 
    '<radialGradient id="gradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">' +
    '    <stop offset="0%" style="stop-color:#568f82;stop-opacity:1" />' +
    '    <stop offset="100%" style="stop-color:#568f82;stop-opacity:0" />' +
    '</radialGradient>';

似乎innerHTML不是SVGElement的属性。

3 个答案:

答案 0 :(得分:2)

var parser = new DOMParser();
var doc = parser.parseFromString(stringContainingXMLSource, "image/svg+xml");

请注意,父节点需要具有显式名称空间,以便正确解析它,即字符串需要如下所示:

var stringContainingXMLSource = '<radialGradient xmlns="http://www.w3.org/2000/svg" id="gradient" ...

然后你可以做

defs.appendChild(document.importNode(doc.documentElement));

有些UA也允许doc.rootElement而不是doc.documentElement,但显然不是全部。

答案 1 :(得分:1)

没有直接标记属性,但您可以使用DOMParser.parseFromString()将某些XML解析为新的SVG文档,并importNode将其解析。或者,您可以使用innerHTML设置容器HTML元素的内容,并将SVG节点拉出结果。

但是,字符串吊索有点笨拙 - 只要您想引入可变内容或属性值,就可以轻松地进行字符串连接而不记住正确的转义,从而导致跨站点脚本问题。能够将所有内容保存在对象和属性的世界中,而不是编码标记,这很好。

不可否认,uber-verbose DOM API并不容易,但您可以编写快捷函数来为您调用DOM方法,允许您编写类似的内容:

xml(SVG, 'defs', {}, [
    xml(SVG, 'radialGradient', {id: 'gradient', cx: '50%', cy: '50%', fx: '50%', fy: '50%' r: '50%'}, [
        xml(SVG, 'path', {offset:   '0%', 'stop-color': '#568f82', 'stop-opacity': 1}),
        xml(SVG, 'path', {offset: '100%', 'stop-color': '#568f82', 'stop-opacity': 0})
    ])
])

这更容易应对。

答案 2 :(得分:0)

如果您想要更简洁的语法并且愿意使用库,请考虑尝试Raphaëlsvg.js