2012-03-15 38 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