2012-03-15 67 views
14

在HTML中,我可以通过以字符串形式提供模板来构建一个简单的模板系统,替换它的某些部分,然后使用innerHTML将它分配给某个容器。SVG/XML中有一些innerHTML替换吗?

var templ = '<span>{myText}</span>' 
var newContent = templ.replace('{myText}', someVariable); 
document.querySelector('#myContainer').innerHTML = newContent; 

这样我可以利用浏览器的HTML解析器,并没有重复使用document.createElement()。如果模板增长超过几个元素,后者可能非常麻烦。

但是,在SVG中,对于这个问题,元素没有innerHTML甚至innerSVG的属性。

所以我的问题是:有什么我可以在SVG中使用ro类似于上面的例子的方法,或者我坚持与document.createElement()(或分别使用它的一些lib)?

一如既往的我的问题:香草JavaScript解决方案是首选,但任何指向提供解决方案的lib的指针表示赞赏。

回答

10

可以使用的DOMParser来解析XML:https://developer.mozilla.org/en/Parsing_and_serializing_XML那么你可以使用importNode来获取到您现有的文件,如果你想:https://developer.mozilla.org/en/DOM/document.importNode结束了这样的事情...

var doc = new DOMParser().parseFromString(
    '<svg xmlns="http://www.w3.org/2000/svg"><circle cx="100" cy="100" r="20"/></svg>', 
    'application/xml'); 

someElement.appendChild(
someElement.ownerDocument.importNode(doc.documentElement, true)); 
+0

这需要片段为有效的XML文档(仅限单根),对吗?而对于不具有适当名称空间的SVG元素的片段,所创建的元素是否具有正确的名称空间? – Phrogz 2012-03-15 18:55:59

+0

您可能希望/需要将其包装为一个函数,该函数将字符串包装到SVG根目录中,并预定义所有通用名称空间和前缀,然后提取内容。 – Phrogz 2012-03-15 18:57:35

+0

是的,这个片段需要一个名称空间属性。 – 2012-03-15 22:32:05

1

使用jQuery,你可以这样说:

我们假设你的svgString包含更换操作后,你的SVG图像。

$(svgString)[0]创建与您的字符串对应的svg标签。然后你可以在dom中想要的位置添加这个元素来绘制图像。

我希望这有助于

+0

您确定这会在适当的命名空间中创建元素吗? – Phrogz 2012-03-15 18:54:38

3

简短的回答是“不,在XML的世界中没有任何等价物可以让你给它一些标记,并让它自动创建所有的元素和属性在适当的名称空间中插入的位置它。”

最接近的直接答案是@罗伯特有什么。正如我的评论中指出的那样,即使这样,您仍然需要在SVG文档中创建与您要插入片段的文档具有相同名称空间和前缀的片段。

相反,你可能会发现它是那么容易(或容易)使用的便捷方法的标准DOM方法:

// Create a named SVG element on a node, with attributes and optional text 
function appendTo(node,name,attrs,text){ 
    var p,ns=appendTo.ns,svg=node,doc=node.ownerDocument; 
    if (!ns){ // cache namespaces by prefix once 
    while (svg&&svg.tagName!='svg') svg=svg.parentNode; 
    ns=appendTo.ns={svg:svg.namespaceURI}; 
    for (var a=svg.attributes,i=a.length;i--;){ 
     if (a[i].namespaceURI) ns[a[i].localName]=a[i].nodeValue; 
    } 
    } 
    var el = doc.createElementNS(ns.svg,name); 
    for (var attr in attrs){ 
    if (!attrs.hasOwnProperty(attr)) continue; 
    if (!(p=attr.split(':'))[1]) el.setAttribute(attr,attrs[attr]); 
    else el.setAttributeNS(ns[p[0]]||null,p[1],attrs[attr]); 
    } 
    if (text) el.appendChild(doc.createTextNode(text)); 
    return node.appendChild(el); 
} 

function clear(node){ 
    while (node.lastChild) node.removeChild(node.lastChild); 
} 

有了这个,你可以做这样的事情:

var icons={ 
    Apps : "/images/apps.png", 
    Games : "/images/games.png" 
} 
var wrap = document.querySelector('#container'); 
clear(wrap); 

for (var label in icons){ 
    if (!icons.hasOwnProperty(label)) continue; 
    var icon = appendTo(wrap,'g',{'class':'icon'}); 
    appendTo(icon,'image',{'xlink:href':icons[label]}); 
    appendTo(icon,'text',{x:10,y:20},label); 
} 

这是恕我直言,比尝试使用字符串连接构造原始SVG标记更清洁:

var svg = []; 
for (var label in icons){ 
    if (!icons.hasOwnProperty(label)) continue; 
    svg.push('<g class="icon">'); 
    svg.push('<image xlink:href="'+icons[label]+'" />'); 
    svg.push('<text x="10" y="20">'+label+'</text>'); 
    svg.push('</g>'); 
} 
wrap.innerSVG = svg.join(''); // doesn't work, of course 
4

C剔除了innerSVG javascript填充程序,它提供了您想要的功能。

2014更新:DOM parsing specElement,这使得这些可用对SVG和XML元素定义innerHTMLouterHTML。这已经在Blink出货一段时间了,支持这个的第一个版本是Chrome 32/Opera 19,更多详细信息可以在this bugreport中找到。

+0

嘿,你知道是否有一种方法让innerSVG与中的SVG一起工作?似乎它只适用于内联svg,而我们的东西目前只适用于一个的SVG ...谢谢。 – nroose 2015-06-29 22:13:14

+0

@nroose是的,这是可能的,请参阅http://xn--dahlstrm-t4a.net/svg/html/get-embedded-svg-document-script.html。如果您无法使用它,请发布一个新问题。 – 2015-06-30 08:31:57

4

我的innerSVG垫片怎么样? CoffeeScript的源代码如下,编译JavaScript是在https://gist.github.com/2648095

# Important: You must serve your pages as XHTML for this shim to work, 
# otherwise namespaced attributes and elements will get messed up. 
Object.defineProperty SVGElement.prototype, 'innerHTML', 
    get:() -> 
    $temp = document.createElement 'div' 
    $node = @cloneNode true 

    for $child in $node.children 
     $temp.appendChild $child 

    return $temp.innerHTML 

    set: (markup) -> 
    while @firstChild 
     @firstChild.parentNode.removeChild @firstChild 

    markup = "<svg id='wrapper' xmlns='http://www.w3.org/2000/svg'>#{markup}</svg>" 
    $div = document.createElement 'div' 
    $div.innerHTML = markup 
    $svg = $div.querySelector 'svg#wrapper' 

    for $element in $svg.children 
     @appendChild $element 
    enumerable : false 
    configurable : true 
1

看起来至少在Chrome和Safari浏览器,你可以在一个HTML元素包装你的SVG元素,并要求innerHTML。即使SVG源指定为绿色,以下HTML文件也会呈现红色矩形。

<body> 
<div id="wrapper"> 
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="120" height="120" viewBox="0 0 236 120"> 
    <rect x="14" y="23" width="250" height="50" fill="green" stroke="black" stroke-width="1" /> 
    </svg> 
</div> 
<script> 
    var el = document.getElementById('wrapper'); 
    var t = el.innerHTML; 
    t = t.replace(/green/g, "red"); 
    el.innerHTML = t; 
</script> 
</body> 
4

这里我写一个肮脏的方式...

innerHTML的解决方法SVG

http://jsfiddle.net/microbians/8ztNU/

<html> 
    <body> 
     <svg id="svgcanvas"> 
     </svg> 
     <script> 
      var twocircles='<circle cx="253" cy="562" r="10" stroke="black" stroke-width="2" fill="red"></circle> \ 
      <circle cx="353" cy="562" r="10" stroke="black" stroke-width="2" fill="red"></circle>' 
      var receptacle = document.createElement('div'); 
      var svgfragment='<svg>'+twocircles+'</svg>'; 
      receptacle.innerHTML=''+svgfragment; 
      var Nodes=Array.prototype.slice.call(receptacle.childNodes[0].childNodes); 
      Nodes.forEach(function(el){document.getElementById('svgcanvas').appendChild(el)}) 
     </script> 
    </body> 
</html> 

享受!

0

更简单地说,document.querySelector('#myContainer').textContent = newContent;有很好的支持,def。到IE9 +,Safari,FF,Chrome。

迈克·博斯托克是我对这类事物的英雄:D3.js source code是我对于SVG问题的一个指导。

+0

'innerHTML'除了设置节点的文本值之外,还具有一些功能,但会触发HTML解析。所以我认为我无法通过使用“textContent”来添加新节点。 – Sirko 2015-05-29 04:44:38

+0

好的。是的,我通常使用'document.createElement(...)',但可以编写一个处理它的函数。 – AJFarkas 2015-06-01 20:33:37