jquery附加不使用svg元素?

196 jquery html5 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>
Run Code Online (Sandbox Code Playgroud)

为什么我什么都没看到?

bob*_*nce 240

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

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

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

但是,对于今天的浏览器,您必须使用X HTML(正确地作为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>
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

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

  • 使用DOM方法createElementNS创建SVG元素后,可以使用jquery操作它们.您可以将makeSVG函数更改为'return $(el)',现在您有一个可以使用jquery方法的svg元素. (6认同)
  • 啊! 所以这就是为什么它不起作用.我用两个不同的库尝试了完全相同的东西,一个在jQuery中,一个在[D3.js](http://d3js.org)中.我在HTML中使用两者完全相同的源输出*,但是在生成D3的元素时,jQuery生成的元素不会呈现!我推荐使用D3:`d3.select('body').append('svg').attr('width','100%');` (6认同)
  • 这个答案仍然有用!我只是有一个奇怪的错误,其中添加的元素显示在Chrome元素检查器中,但不会呈现.如果我在html标签上``RMB`>`编辑为html`并按Enter键显示所有内容(但所有事件监听器都会消失).看完这个答案后,我将createElement调用改为createElementNS,现在一切正常! (5认同)
  • @MadsSkjern:DOM Level 3 LS从未进入过浏览器.最初只支持Mozilla的[DOMParser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser)得到了更广泛的支持,而jQuery有`$ .parseXML`. (3认同)

Tim*_*nen 144

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

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

$("body").html($("body").html());
Run Code Online (Sandbox Code Playgroud)

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

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

$("#cont").html($("#cont").html());
Run Code Online (Sandbox Code Playgroud)

并将你的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>
Run Code Online (Sandbox Code Playgroud)

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

这项技术的优点:

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

编辑:

上述技术仅适用于"硬编码"或DOM操作(= document.createElementNS等)SVG.如果Raphael用于创建元素,(根据我的测试),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)");
Run Code Online (Sandbox Code Playgroud)

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

(我(还)不知道,为什么$("#cont").html($("#cont").html());在使用Raphael时不起作用.这将是非常短暂的黑客攻击.)

  • `$("#cont").html($("#cont").html());` 在 Chrome 中运行良好,但在 IE 11 中不适用于我。 (2认同)

nat*_*ood 37

越来越流行的D3库非常好地处理了追加/操纵svg的奇怪之处.你可能想考虑使用它而不是这里提到的jQuery hacks.

HTML

<svg xmlns="http://www.w3.org/2000/svg"></svg>
Run Code Online (Sandbox Code Playgroud)

使用Javascript

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


for*_*sto 25

JQuery无法追加元素<svg>(它似乎将它们添加到DOM资源管理器中,但不会添加到屏幕上).

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

$('body')
  .append($('<svg><circle id="c" cx="10" cy="10" r="10" fill="green" /></svg>'))
  .mousemove( function (e) {
      $("#c").attr({
          cx: e.pageX,
          cy: e.pageY
      });
  });
Run Code Online (Sandbox Code Playgroud)

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


Chr*_*hin 16

我没有看到有人提到这种方法但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);
Run Code Online (Sandbox Code Playgroud)

唯一的缺点是你必须单独创建具有正确命名空间的每个SVG元素,否则它将无法工作.

  • 蒂莫的答案(最高投票)在Chrome中有效,但不是IE.这个答案解决了两个浏览器的问题! (2认同)
  • 好的!很高兴知道 (2认同)

Mat*_*ier 11

找到一种适用于我所有浏览器的简单方法(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('<polygon class="svgStyle" points="10,10 50,10 50,50 10,50 10,10" />');
$('#svgObject').append('<circle class="svgStyle" cx="100" cy="30" r="25"/>');

// Magic happens here: refresh DOM (you must refresh svg's parent for Edge/IE and Safari)
$('#svgContainer').html($('#svgContainer').html());
Run Code Online (Sandbox Code Playgroud)
.svgStyle
{
  fill:cornflowerblue;
  fill-opacity:0.2;
  stroke-width:2;
  stroke-dasharray:5,5;
  stroke:black;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="svgContainer">
  <svg id="svgObject" height="100" width="200"></svg>
</div>

<span>It works if two shapes (one square and one circle) are displayed above.</span>
Run Code Online (Sandbox Code Playgroud)

  • 刷新线正是我想要的.傻浏览器.谢谢! (4认同)

Top*_*era 8

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

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

2)将脚本更改为

<script type="text/javascript">
$(document).ready(function(){
    var obj = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    obj.setAttributeNS(null, "cx", 100);
    obj.setAttributeNS(null, "cy", 50);
    obj.setAttributeNS(null, "r",  40);
    obj.setAttributeNS(null, "stroke", "black");
    obj.setAttributeNS(null, "stroke-width", 2);
    obj.setAttributeNS(null, "fill", "red");
    $("svg")[0].appendChild(obj);
});
</script>
Run Code Online (Sandbox Code Playgroud)

  • 八年后,这仍然很有帮助! (2认同)

Jon*_*lin 5

基于@ 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);
Run Code Online (Sandbox Code Playgroud)