jquery的追加不与svg元素一起工作?

假设:

<html>
<head>
 <script type="text/javascript" src="jquery.js"></script>
 <script type="text/javascript">
 $(document).ready(function(){
  $("svg").append('<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>');
 });
 </script>
</head>
<body>
 <svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" width="200px" height="100px">
 </svg>
</body>

为什么我看不到任何东西?


当您将标记字符串传递到$ ,它会使用浏览器的<div> (或其他适当的容器,用于特殊情况下的<tr> )的innerHTML属性解析为HTML。 innerHTML无法解析SVG或其他非HTML内容,即使它可能无法分辨<circle>应该在SVG名称空间中。

innerHTML在SVGElement上不可用 - 它仅是HTMLElement的一个属性。 目前还没有innerSVG属性或其他方式(*)来解析SVGElement的内容。 出于这个原因,你应该使用DOM风格的方法。 jQuery不会让您轻松访问创建SVG元素所需的名称空间方法。 真的,jQuery并非设计用于SVG,许多操作可能会失败。

HTML5承诺可以让您在未来使用<svg>而无需在纯HTML( text/html )文档中使用xmlns 。 但这只是一个解析器hack(**),SVG内容仍然是SVG命名空间中的SVGElements,而不是HTMLElements,所以即使它们看起来像HTML文档的一部分,也不能使用innerHTML

但是,对于今天的浏览器,您必须使用XHTML(正确地作为application/xhtml+xml ;保存为本地测试的.xhtml文件扩展名)才能让SVG正常工作。 (无论如何它都是有意义的; SVG是一个正确的基于XML的标准。)这意味着你必须转义脚本块中的<符号(或者包含在CDATA部分中),并且包含XHTML xmlns声明。 例:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head>
</head><body>
    <svg id="s" xmlns="http://www.w3.org/2000/svg"/>
    <script type="text/javascript">
        function makeSVG(tag, attrs) {
            var el= document.createElementNS('http://www.w3.org/2000/svg', tag);
            for (var k in attrs)
                el.setAttribute(k, attrs[k]);
            return el;
        }

        var circle= makeSVG('circle', {cx: 100, cy: 50, r:40, stroke: 'black', 'stroke-width': 2, fill: 'red'});
        document.getElementById('s').appendChild(circle);
        circle.onmousedown= function() {
            alert('hello');
        };
    </script>
</body></html>

*:好吧,DOM Level 3 LS的parseWithContext,但浏览器支持很差。 编辑添加:但是,虽然无法将标记注入SVGElement,但可以使用innerHTML将新的SVGElement注入HTMLElement,然后将其转移到所需的目标。 它可能会稍微慢一些:

<script type="text/javascript"><![CDATA[
    function parseSVG(s) {
        var div= document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
        div.innerHTML= '<svg xmlns="http://www.w3.org/2000/svg">'+s+'</svg>';
        var frag= document.createDocumentFragment();
        while (div.firstChild.firstChild)
            frag.appendChild(div.firstChild.firstChild);
        return frag;
    }

    document.getElementById('s').appendChild(parseSVG(
        '<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" onmousedown="alert('hello');"/>'
    ));
]]></script>

**:我讨厌HTML5的作者似乎对XML感到害怕,并决定将基于XML的特性压缩到HTML这种重要的混乱中。 XHTML多年前解决了这些问题。


接受的答案显示过于复杂。 正如Forresto在他的回答中所声称的那样,“它似乎将它们添加到DOM浏览器中,但不在屏幕上”,原因是html和svg具有不同的名称空间。

最简单的解决方法是“刷新”整个svg。 附加圆圈(或其他元素)后,使用以下内容:

$("body").html($("body").html());

这是诀窍。 圆圈在屏幕上。

或者,如果你想使用一个容器div:

$("#cont").html($("#cont").html());

并将你的svg包装在容器div中:

<div id="cont">
    <svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" width="200px" height="100px">
    </svg>
</div>

功能示例:
http://jsbin.com/ejifab/1/edit

这种技术的优点:

  • 你可以编辑现有的svg(已经在DOM中),例如。 在您的示例中使用Raphael或类似的“硬编码”创建,无需编写脚本。
  • 你可以添加复杂的元素结构作为字符串例如。 $('svg').prepend('<defs><marker></marker><mask></mask></defs>'); 就像你在jQuery中做的一样。
  • 在元素被附加后,使用$("#cont").html($("#cont").html());在屏幕上可见$("#cont").html($("#cont").html()); 他们的属性可以使用jQuery进行编辑。

  • 编辑:

    上述技术仅适用于“硬编码”或DOM操作(= document.createElementNS等)SVG。 如果使用Raphael创建元素,(根据我的测试),如果$("#cont").html($("#cont").html());则断开Raphael对象与SVG DOM之间的链接$("#cont").html($("#cont").html()); 用来。 解决方法是不使用$("#cont").html($("#cont").html()); 根本不使用虚拟SVG文档。

    这个虚拟SVG首先是SVG文档的文本表示,并且仅包含所需的元素。 如果我们想要例如。 为Raphael文档添加一个过滤元素,该虚拟元素可以是类似于<svg id="dummy" style="display:none"><defs><filter><!-- Filter definitons --></filter></defs></svg> 。 文本表示首先使用jQuery的$(“body”)。append()方法转换为DOM。 当(filter)元素在DOM中时,可以使用标准jQuery方法查询它,并附加到由Raphael创建的主SVG文档。

    为什么需要这个假人? 为什么不向Raphael创建的文档严格添加滤镜元素? 如果你尝试使用例如。 $("svg").append("<circle ... />") ,它被创建为html元素,屏幕上没有任何东西在答案中描述。 但是如果附加了整个SVG文档,浏览器会自动处理SVG文档中所有元素的名称空间转换。

    一个启发技术的例子:

    // Add Raphael SVG document to container element
    var p = Raphael("cont", 200, 200);
    // Add id for easy access
    $(p.canvas).attr("id","p");
    // Textual representation of element(s) to be added
    var f = '<filter id="myfilter"><!-- filter definitions --></filter>';
    
    // Create dummy svg with filter definition 
    $("body").append('<svg id="dummy" style="display:none"><defs>' + f + '</defs></svg>');
    // Append filter definition to Raphael created svg
    $("#p defs").append($("#dummy filter"));
    // Remove dummy
    $("#dummy").remove();
    
    // Now we can create Raphael objects and add filters to them:
    var r = p.rect(10,10,100,100);
    $(r.node).attr("filter","url(#myfilter)");
    

    这项技术的完整工作演示在这里:http://jsbin.com/ilinan/1/edit。

    (我还没有想过,为什么$("#cont").html($("#cont").html());在使用Raphael时不起作用,这将会非常短暂。


    日益流行的D3库非常好地处理了添加/操作svg的古怪事情。 你可能要考虑使用它,而不是这里提到的jQuery hack。

    HTML

    <svg xmlns="http://www.w3.org/2000/svg"></svg>
    

    使用Javascript

    var circle = d3.select("svg").append("circle")
        .attr("r", "10")
        .attr("style", "fill:white;stroke:black;stroke-width:5");
    
    链接地址: http://www.djcxy.com/p/49173.html

    上一篇: jquery's append not working with svg element?

    下一篇: Can I find events bound on an element with jQuery?