假设:
<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>
为什么我什么都看不到?
答案 0 :(得分:235)
当您将标记字符串传递到$
时,它会使用innerHTML
上的浏览器<div>
属性(或其他适用于<tr>
等特殊情况的容器解析为HTML )。 innerHTML
无法解析SVG或其他非HTML内容,即使它可能无法告知<circle>
应该在SVG名称空间中。
innerHTML
在SVGElement上不可用 - 它只是HTMLElement的属性。目前还没有innerSVG
属性或其他方式(*)来将内容解析为SVGElement。因此,您应该使用DOM样式的方法。 jQuery不能让您轻松访问创建SVG元素所需的命名空间方法。实际上,jQuery根本不适合与SVG一起使用,许多操作可能会失败。
HTML5承诺将来允许您在纯HTML(<svg>
)文档中使用xmlns
而不使用text/html
。但这只是一个解析器hack(**),SVG内容仍然是SVG名称空间中的SVGElements,而不是HTMLElements,所以即使他们看起来<<1},你也无法使用innerHTML
/ em>喜欢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>
*:嗯,有DOM Level 3 LS的parseWithContext,但浏览器支持非常差。编辑添加:但是,虽然您无法将标记注入SVGElement,但您可以使用innerHTML
将新的SVGE元素注入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在几年前解决了这些问题。
答案 1 :(得分:137)
accepted answer表现得过于复杂。正如Forresto在his answer中声称的那样,“它似乎确实将它们添加到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').prepend('<defs><marker></marker><mask></mask></defs>');
。 $("#cont").html($("#cont").html());
在屏幕上显示后,可以使用jQuery编辑它们的属性。 编辑:
上述技术仅适用于“硬编码”或DOM操作(= document.createElementNS等)SVG。如果Raphael用于创建元素,(根据我的测试),如果使用$("#cont").html($("#cont").html());
,Raphael对象和SVG DOM之间的链接将被破坏。解决方法是不要使用$("#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时不起作用。这将是非常简短的黑客攻击。)
答案 2 :(得分:36)
越来越受欢迎的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");
答案 3 :(得分: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
});
});
答案 4 :(得分:14)
我没有看到有人提到这种方法,但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元素,否则它将无法工作。
答案 5 :(得分:9)
找到了一种适用于我所有浏览器的简单方法(Chrome 49,Edge 25,Firefox 44,IE11,Safari 5 [Win],Safari 8(MacOS)):
.svgStyle
{
fill:cornflowerblue;
fill-opacity:0.2;
stroke-width:2;
stroke-dasharray:5,5;
stroke:black;
}
&#13;
<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>
&#13;
perl
&#13;
答案 6 :(得分: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>
答案 7 :(得分: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);
答案 8 :(得分:4)
如果您需要附加的字符串是SVG并且添加了正确的命名空间,则可以将该字符串解析为XML并附加到父字符串。
var xml = jQuery.parseXML('<circle xmlns="http://www.w3.org/2000/svg" cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>');
$("svg").append(xml.documentElement))
答案 9 :(得分:3)
Bobince接受的答案是一个简短的便携式解决方案。如果您不仅需要附加SVG而且还要操纵它,您可以尝试JavaScript library "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');
答案 10 :(得分:1)
我建议使用ajax并从另一页加载svg元素会更好。
$('.container').load(href + ' .svg_element');
其中href是带有svg的页面的位置。这样,您可以避免替换html内容可能引起的任何抖动效果。另外,别忘了在svg加载后将其解开:
$('.svg_element').unwrap();
答案 11 :(得分:0)
今天这对我来说很有用,我们用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");
}
制作:
答案 12 :(得分:0)
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: <circle> for example requires attributes to render. Check if missing.
答案 13 :(得分:0)
我为此做了一个小功能。对于 jQuery append 方法,问题是需要为 SVG 指定命名空间,即 "http://www.w3.org/2000/svg"
More
那么如果我为 append 方法准备它呢?在这种情况下,您唯一需要提供的是一些参数,例如:
tagName
:它可以是每个 SVG 元素,如 rect、circle、text、g 等。
text
:如果您使用文本标记名之类的内容,则需要指定文本
SVG 元素的其他已知属性。
因此我要做的是定义一个名为 createSvgElem()
的函数,它在内部使用 document.createElementNS()。
这是一个例子:
$("svg").append(
createSvgElem({tagName: "text", x: 10, y: 10, text: "ABC", style: "fill: red"})
)
这是函数:
function createSvgElem(options){
var settings = $.extend({
}, options);
if(!$.isEmptyObject(settings.tagName)){
var el = document.createElementNS('http://www.w3.org/2000/svg', settings.tagName);
for (var k in settings)
if(k != "tagName" && k != "text" && settings[k] != "")//If attribute has value
el.setAttribute(k, settings[k]);
if ("text" in settings)
el.textContent = settings.text; //el.innerText; For IE
return el;
}
}
在这里你可以自己尝试:
//Definition:
function createSvgElem(options){
var settings = $.extend({
}, options);
if(!$.isEmptyObject(settings.tagName)){
var el = document.createElementNS('http://www.w3.org/2000/svg', settings.tagName);
for (var k in settings)
if(k != "tagName" && k != "text" && settings[k] != "")//If attribute has value
el.setAttribute(k, settings[k]);
if ("text" in settings)
el.textContent = settings.text; //el.innerText; For IE
return el;
}
}
//Usage:
$(function(){
$("#svg-elem").append(
createSvgElem({tagName: "rect", width: 130, height: 500, style: "fill: #000000a3;"})
)
$("#svg-elem").append(
createSvgElem({tagName: "text", x: 30, y: 30, text: "ABCD", style: "fill: red"})
)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg id="svg-elem" width="200" height="200">
</svg>
答案 14 :(得分:-1)
更简单的方法是将SVG生成为字符串,创建包装HTML元素并使用$("#wrapperElement").html(svgString)
将svg字符串插入HTML元素。这在Chrome和Firefox中运行良好。