jquery的附加不使用svg元素?

假设这个:

    $(document).ready(function(){ $("svg").append(''); });       

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

当您将标记字符串传递给$ ,它会使用浏览器的

上的innerHTML属性(或其他适用于

等特殊情况的容器)解析为HTML。 innerHTML无法解析SVG或其他非HTML内容,即使它可能无法告诉应该在SVG名称空间中。

innerHTML在SVGElement上不可用 – 它只是HTMLElement的属性。 目前还没有内部innerSVG属性或其他方式(*)来将内容解析为SVGElement。 因此,您应该使用DOM样式的方法。 jQuery不允许您轻松访问创建SVG元素所需的命名空间方法。 实际上jQuery根本不适合与SVG一起使用,许多操作可能会失败。

HTML5承诺将来允许您在纯HTML( text/html )文档中使用而不使用xmlns 。 但这只是一个解析器hack(**),SVG内容仍然是SVG名称空间中的SVGElements,而不是HTMLElements,所以即使它们看起来像是HTML文档的一部分,你也无法使用innerHTML

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

       

*:嗯,有DOM Level 3 LS的parseWithContext ,但浏览器支持很差。 编辑添加:但是,虽然您无法将标记注入SVGElement,但您可以使用innerHTML将新的SVGElement注入HTMLElement,然后将其传输到所需的目标。 它可能会慢一点:

  

**:我讨厌HTML5的作者似乎害怕XML的方式,并决心将基于XML的function扼杀到HTML这个繁琐的混乱中。 XHTML多年前解决了这些问题。

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

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

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

这样就可以了。 圆圈在屏幕上。

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

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

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

 

function示例:
http://jsbin.com/ejifab/1/edit

这种技术的优点:

  • 你可以编辑现有的svg(已经在DOM中),例如。 使用Raphael创建或在您的示例中使用“硬编码”而无需编写脚本。
  • 你可以添加复杂的元素结构作为字符串,例如 $('svg').prepend(''); 就像你在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文档添加过滤元素,虚拟对象可能类似于 。 文本表示首先使用jQuery的$(“body”)。append()方法转换为DOM。 当(filter)元素在DOM中时,可以使用标准jQuery方法查询它并将其附加到由Raphael创建的主SVG文档中。

为什么需要这个假人? 为什么不严格添加过滤元素到Raphael创建的文档? 如果您尝试使用例如。 $("svg").append("") ,它被创建为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 = ''; // Create dummy svg with filter definition $("body").append(''); // 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 hacks。

HTML

  

使用Javascript

 var circle = d3.select("svg").append("circle") .attr("r", "10") .attr("style", "fill:white;stroke:black;stroke-width:5"); 

JQuery无法将元素附加到 (它似乎确实将它们添加到DOM资源管理器中,但不会添加到屏幕上)。

一种解决方法是将附加到页面所需的所有元素,然后使用.attr()修改元素的属性。

 $('body') .append($('')) .mousemove( function (e) { $("#c").attr({ cx: e.pageX, cy: e.pageY }); }); 

http://jsfiddle.net/8FBjb/1/

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

您可以使用vanilla Javascript创建元素作为具有正确名称空间的普通DOM节点,然后从那里使用jQuery-ify。 像这样:

 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元素,否则它将无法工作。

我可以在firefox中看到圈子,做两件事:

1)将文件从html重命名为xhtml

2)将脚本更改为

  

找到一种适用于我所有浏览器的简单方法(Chrome 49,Edge 25,Firefox 44,IE11,Safari 5 [Win],Safari 8(MacOS)):

 // Clean svg content (if you want to update the svg's objects) // Note : .html('') doesn't works for svg in some browsers $('#svgObject').empty(); // add some objects $('#svgObject').append(''); $('#svgObject').append(''); // Magic happens here: refresh DOM (you must refresh svg's parent for Edge/IE and Safari) $('#svgContainer').html($('#svgContainer').html()); 
 .svgStyle { fill:cornflowerblue; fill-opacity:0.2; stroke-width:2; stroke-dasharray:5,5; stroke:black; } 
  
It works if two shapes (one square and one circle) are displayed above.

基于@ chris-dolphin的答案,但使用辅助函数:

 // Creates svg element, returned as jQuery object function $s(elem) { return $(document.createElementNS('http://www.w3.org/2000/svg', elem)); } var $svg = $s("svg"); var $circle = $s("circle").attr({...}); $svg.append($circle); 

如果您需要附加的字符串是SVG并且您添加了正确的命名空间,则可以将该字符串解析为XML并附加到父级。

 var xml = jQuery.parseXML(''); $("svg").append(xml.documentElement)) 

Bobince接受的答案是一个简短的便携式解决方案。 如果您不仅需要附加SVG而且还需要操作它,您可以尝试使用JavaScript库“Pablo” (我写了它)。 jQuery用户会觉得很熟悉。

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

 $(document).ready(function(){ Pablo("svg").append(''); }); 

您还可以动态创建SVG元素,而无需指定标记:

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

我建议使用ajax并从另一个页面加载svg元素可能会更好。

 $('.container').load(href + ' .svg_element'); 

其中href是带有svg的页面的位置。 这样您就可以避免替换html内容时可能出现的任何抖动。 此外,不要忘记在加载后打开svg:

 $('.svg_element').unwrap(); 
  var svg; // if you have variable declared and not assigned value. // then you make a mistake by appending elements to that before creating element svg.appendChild(document.createElement("g")); // at some point you assign to svg svg = document.createElementNS('http://www.w3.org/2000/svg', "svg") // then you put it in DOM document.getElementById("myDiv").appendChild(svg) // it wont render unless you manually change myDiv DOM with DevTools // to fix assign before you append var svg = createElement("svg", [ ["version", "1.2"], ["xmlns:xlink", "http://www.w3.org/1999/xlink"], ["aria-labelledby", "title"], ["role", "img"], ["class", "graph"] ]); function createElement(tag, attributeArr) { // .createElementNS NS is must! Does not draw without let elem = document.createElementNS('http://www.w3.org/2000/svg', tag); attributeArr.forEach(element => elem.setAttribute(element[0], element[1])); return elem; } // extra:  for example requires attributes to render. Check if missing. 

这对我今天的FF 57有用:

 function () { // JQuery, today, doesn't play well with adding SVG elements - tricks required $(selector_to_node_in_svg_doc).parent().prepend($(this).clone().text("Your")); $(selector_to_node_in_svg_doc).text("New").attr("x", "340").text("New") .attr('stroke', 'blue').attr("style", "text-decoration: line-through"); } 

使得:

这个SVG图像如Firefox 57所示

一种更简单的方法是将SVG生成为字符串,创建包装HTML元素并使用$("#wrapperElement").html(svgString)将svg字符串插入HTML元素。 这在Chrome和Firefox中运行良好。