假设:

<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>

为什么我什么都看不到?


当前回答

越来越流行的D3库很好地处理了附加/操作svg的奇怪问题。您可能会考虑使用它,而不是这里提到的jQuery hacks。

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");

其他回答

Bobince给出的公认答案是一个简短的、可移植的解决方案。如果您不仅需要添加SVG,而且还需要操作它,那么可以尝试JavaScript库“Pablo”(它是我编写的)。jQuery用户会感觉很熟悉。

您的代码示例将如下所示:

$(document).ready(function(){
    Pablo("svg").append('<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>');
});

你也可以动态地创建SVG元素,而不需要指定标记:

var circle = Pablo.circle({
    cx:100,
    cy:50,
    r:40
}).appendTo('svg');

我还没见过有人提到这个方法,但是document.createElementNS()在这个实例中很有帮助。

您可以使用普通Javascript将元素创建为具有正确名称空间的普通DOM节点,然后从那里对它们进行jquery化。像这样:

var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
    circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');

var $circle = $(circle).attr({ //All your attributes });

$(svg).append($circle);

唯一的缺点是您必须使用正确的名称空间单独创建每个SVG元素,否则它将无法工作。

替代方案1:原生js insertAdjacentHTML()

如果你根本不考虑切换到原生JavaScript…… 您还可以使用本地javaScript方法insertAdjacentHTML()来获得同样方便的表示法。

  $("#svg")[0].insertAdjacentHTML(
    "beforeEnd",
    '<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>'
  );

$("#svg")[0]使你的jQuery对象在原生JS中可选。

替代方案2:编写一个原生js DOMParser()帮助器

mdn web文档:DOMParser.parseFromString()

  function createSvgEl(markup) {
    markup = `<svg xmlns="http://www.w3.org/2000/svg">
  ${markup}</svg>`;
    const svgEl = new DOMParser().parseFromString(markup, "image/svg+xml")
      .documentElement.children[0];
    return svgEl;
  }

jQuery的用法:

  $("#svgXML").append(
    createSvgEl(
      '<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>'
    )
  );

Demo

// native js helper function createSvgEl(markup) { markup = `<svg xmlns="http://www.w3.org/2000/svg"> ${markup}</svg>`; const svgEl = new DOMParser().parseFromString(markup, "image/svg+xml") .documentElement.children[0]; return svgEl; } $(document).ready(function() { // works - but will remove existing children $("#svg1").html( '<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>' ); // works // $("#svg")[0] makes your jQueryObject selectable in native JS $("#svg")[0].insertAdjacentHTML( "beforeEnd", '<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>' ); $("#svgXML").append( createSvgEl( '<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>' ) ); // jquery still works! Vanilla doesn't harm! $("#svgXML circle:nth-of-type(2)").attr('fill', 'orange'); //insert after() $("#svgAfter circle").after( createSvgEl( '<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>' ) ); //insert after native $("#svgAfterNative circle")[0].insertAdjacentHTML( "afterEnd", '<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>' ); }); svg { border: 1px solid red; overflow: visible; } <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <p>Append via native js insertAdjacentHTML()</p> <svg id="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"> <circle cx="10" cy="10" r="5" fill="green" /> </svg> <p>Append via DOMParser() helper</p> <svg id="svgXML" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" width="200px" height="100px"> <circle cx="10" cy="10" r="5" fill="green" /> </svg> <p>Append via jquery html() - will strip existing child nodes</p> <svg id="svg1" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" width="200px" height="100px"> <circle cx="10" cy="10" r="5" fill="green" /> </svg> <p>Insert after existing element with jQuery after() using DOMParser() helper</p> <svg id="svgAfter" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" width="200px" height="100px"> <circle cx="10" cy="10" r="5" fill="green" /> </svg> <p>Insert after existing element with native js insertAdjacentHTML()</p> <svg id="svgAfterNative" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" width="200px" height="100px"> <circle cx="10" cy="10" r="5" fill="green" /> </svg>

jquery的after()或before()方法也将无法添加SVG DOM(取决于正确的名称空间)元素。

使用前面提到的变通方法也可以解决这个问题。

一个更简单的方法是将SVG生成为字符串,创建包装器HTML元素,并使用$(“#wrapperElement”). HTML (svgString)将SVG字符串插入到HTML元素中。这在Chrome和Firefox中工作得很好。

公认的答案显得太复杂了。正如Forresto在他的回答中所声称的那样,“它似乎是在DOM资源管理器中添加它们,而不是在屏幕上”,其原因是html和svg的名称空间不同。

最简单的解决方法是“刷新”整个svg。在添加circle(或其他元素)后,使用以下语句:

$("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(“< def > <标记> < / >标记<面具> < /面具> < / def >”);就像在jQuery中一样。 在添加元素并在屏幕上显示后,使用$("#cont").html($("#cont").html());它们的属性可以使用jQuery编辑。


编辑:

上述技术适用于“硬编码”或DOM操纵(= document。仅支持SVG。如果Raphael用于创建元素,(根据我的测试)Raphael对象和SVG DOM之间的链接被破坏,如果$(“#cont”).html($(“#cont”).html());使用。解决方法不是使用$("#cont").html($("#cont").html());而不是使用虚拟SVG文档。

This dummy SVG is first a textual representation of SVG document and contains only elements that are needed. If we want eg. to add a filter element to Raphael document, the dummy could be something like <svg id="dummy" style="display:none"><defs><filter><!-- Filter definitons --></filter></defs></svg>. The textual representation is first converted to DOM using jQuery's $("body").append() method. And when the (filter) element is in DOM, it can be queried using standard jQuery methods and appended to the main SVG document which is created by Raphael.

为什么需要这个假人?为什么不添加一个过滤器元素严格拉斐尔创建的文件?如果你试着用eg。美元(svg)。追加(“<圆…/>"),它被创建为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。

(我有(还)不知道,为什么美元(“#合同”). html($(" #合同”). html ());当使用拉斐尔时不工作。这将是非常短的hack。)