SVG文本的动态样式

gee*_*h01 2 javascript svg d3.js

<svg>
    <text id="test" x="0" y="15"></text>
</svg>
Run Code Online (Sandbox Code Playgroud)

,

d3.select("#test").text("aaa");
Run Code Online (Sandbox Code Playgroud)

要么

document.getElementById("test").textContent("aaa");
Run Code Online (Sandbox Code Playgroud)

工作良好.但我需要在文本中添加样式.现在:

d3.select("#test").text('aaa <tspan style="font-weight:bold">bbb</tspan> ccc');
Run Code Online (Sandbox Code Playgroud)

遗憾的是不起作用,因为参数被视为纯字符串.针对此问题的最佳跨浏览器解决方案是什么?

Juv*_*uve 5

工作方案

主要问题是innerHTMLSVG元素没有属性,您需要自己创建所有子节点.但是,您可以tspan通过仅使用此字符串创建临时DOM对象,将HTML字符串转换为样式s(无)字符串解析魔法.之后,您可以使用d3创建正确的tspans元素.

var text  = d3.select("#test"), tmp = document.createElement("text");  //create tmp
tmp.innerHTML = 'aaa <tspan style="font-weight:bold">bbb</tspan> ccc'  //create HTML children (not yet an SVG!)
var nodes = Array.prototype.slice.call(tmp.childNodes)                 //create a real array from the childNodes variable
nodes.forEach( function(node) {
    text.append("tspan")
        .attr("style", node.getAttribute && node.getAttribute("style"))
        .text(node.textContent)
})
Run Code Online (Sandbox Code Playgroud)

剩余问题:此解决方案不支持tspans中需要遍历childNodes源元素style的子节点,从子节点和append新子tspan元素(以及其他可能的标签)复制(可能还有其他属性)到相应的父节点tspans(或其他标签).这最终会导致一个sub tspan兼容的解析器完全解决这个问题.

编辑:有一个更通用的innerSVG垫片,也可以处理子节点.

破解方案

还有一些其他解决方案应该可行,但目前已被打破.正如其他人已经指出的那样,.html()直接在jQuery或d3中使用是行不通的,因为它们依赖于innerHTML.

//not working
$("#test").html(...); d3.select("#test").html(...)
Run Code Online (Sandbox Code Playgroud)

通过jQuery复制和追加(类似于我的工作解决方案)也被打破了.它创建了正确的DOM,但未显示tspan(在Firefox和Chrome中尝试过):

//creates correct DOM, but disables/hides the created tspan
var tmp = $("<text>")
tmp.html('aaa <tspan style="font-weight:bold">bbb</tspan> ccc')
$("#test").append( Array.prototype.slice.call(tmp[0].childNodes) )
Run Code Online (Sandbox Code Playgroud)

根据W3C规范,应该可以混合使用 tspan和TextNodes.