Ich verwende jQuery SVG. Ich kann keine Klasse zu einem Objekt hinzufügen oder daraus entfernen. Kennt jemand meinen Fehler?
Die SVG:
<rect class="jimmy" id="p5" x="200" y="200" width="100" height="100" />
Die jQuery, die die Klasse nicht hinzufügt:
$(".jimmy").click(function() {
$(this).addClass("clicked");
});
Ich weiß, dass SVG und jQuery gut zusammenarbeiten, weil ich can auf das Objekt ziele und eine Warnung auslöse, wenn darauf geklickt wird:
$(".jimmy").click(function() {
alert('Handler for .click() called.');
});
Edit 2016: Lies die nächsten beiden Antworten.
element.classList.add('newclass')
funktioniert in modernen BrowsernJQuery (weniger als 3) kann einer SVG keine Klasse hinzufügen.
.attr()
funktioniert mit SVG. Wenn Sie also von jQuery abhängen möchten, gehen Sie wie folgt vor:
// Instead of .addClass("newclass")
$("#item").attr("class", "oldclass newclass");
// Instead of .removeClass("newclass")
$("#item").attr("class", "oldclass");
Und wenn Sie sich nicht auf jQuery verlassen möchten:
var element = document.getElementById("item");
// Instead of .addClass("newclass")
element.setAttribute("class", "oldclass newclass");
// Instead of .removeClass("newclass")
element.setAttribute("class", "oldclass");
Es gibt element.classList in der DOM-API, das sowohl für HTML- als auch für SVG-Elemente funktioniert. Keine Notwendigkeit für jQuery SVG-Plugin oder sogar jQuery.
$(".jimmy").click(function() {
this.classList.add("clicked");
});
Eine der Änderungen in der jQuery 3.0-Revision ist:
Eine Lösung für dieses Problem wäre ein Upgrade auf jQuery 3. Es funktioniert hervorragend:
var flip = true;
setInterval(function() {
// Could use toggleClass, but demonstrating addClass.
if (flip) {
$('svg circle').addClass('green');
}
else {
$('svg circle').removeClass('green');
}
flip = !flip;
}, 1000);
svg circle {
fill: red;
stroke: black;
stroke-width: 5;
}
svg circle.green {
fill: green;
}
<script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
<svg>
<circle cx="50" cy="50" r="25" />
</svg>
Der Grund, warum die Manipulationsfunktionen der jQuery-Klasse nicht mit den SVG-Elementen funktionieren, ist, dass jQuery-Versionen vor 3.0 die Eigenschaft className
für diese verwenden funktionen.
attributes/classes.js
:cur = elem.nodeType === 1 && ( elem.className ?
( " " + elem.className + " " ).replace( rclass, " " ) :
" "
);
Dies verhält sich wie erwartet für HTML-Elemente, aber für SVG-Elemente ist className
etwas anders. Bei einem SVG-Element ist className
kein String, sondern eine Instanz von SVGAnimatedString
.
var test_div = document.getElementById('test-div');
var test_svg = document.getElementById('test-svg');
console.log(test_div.className);
console.log(test_svg.className);
#test-div {
width: 200px;
height: 50px;
background: blue;
}
<div class="test div" id="test-div"></div>
<svg width="200" height="50" viewBox="0 0 200 50">
<rect width="200" height="50" fill="green" class="test svg" id="test-svg" />
</svg>
Wenn Sie diesen Code ausführen, wird in Ihrer Entwicklerkonsole Folgendes angezeigt.
test div
SVGAnimatedString { baseVal="test svg", animVal="test svg"}
Wenn wir dieses SVGAnimatedString
-Objekt wie jQuery in einen String umwandeln würden, hätten wir [object SVGAnimatedString]
, bei dem jQuery fehlschlägt.
Das jQuery-SVG-Plugin umgeht dies, indem die relevanten Funktionen gepatcht werden, um SVG-Unterstützung hinzuzufügen.
jquery.svgdom.js
:function getClassNames(elem) {
return (!$.svg.isSVGElem(elem) ? elem.className :
(elem.className ? elem.className.baseVal : elem.getAttribute('class'))) || '';
}
Diese Funktion erkennt, ob ein Element ein SVG-Element ist, und verwendet, falls verfügbar, die Eigenschaft baseVal
des Objekts SVGAnimatedString
, bevor auf das Objekt class
zurückgegriffen wird. Attribut.
jQuery listet dieses Problem derzeit auf der Seite " Won't Fix " auf. Hier sind die relevanten Teile.
SVG/VML oder Namespaced Elements Bugs
jQuery ist in erster Linie eine Bibliothek für das HTML-DOM, sodass die meisten Probleme im Zusammenhang mit SVG/VML-Dokumenten oder Elementen mit Namespace nicht in Betracht kommen. Wir versuchen, Probleme zu beheben, die sich auf HTML-Dokumente auswirken, z. B. Ereignisse, die aus SVG heraussprudeln.
Offensichtlich betrachtete jQuery die volle SVG-Unterstützung als außerhalb des Bereichs des jQuery-Kerns liegend und besser für Plugins geeignet.
Wenn Sie dynamische Klassen haben oder nicht wissen, welche Klassen bereits angewendet werden könnten, ist diese Methode meines Erachtens der beste Ansatz:
// addClass
$('path').attr('class', function(index, classNames) {
return classNames + ' class-name';
});
// removeClass
$('path').attr('class', function(index, classNames) {
return classNames.replace('class-name', '');
});
Basierend auf den obigen Antworten habe ich die folgende API erstellt
/*
* .addClassSVG(className)
* Adds the specified class(es) to each of the set of matched SVG elements.
*/
$.fn.addClassSVG = function(className){
$(this).attr('class', function(index, existingClassNames) {
return ((existingClassNames !== undefined) ? (existingClassNames + ' ') : '') + className;
});
return this;
};
/*
* .removeClassSVG(className)
* Removes the specified class to each of the set of matched SVG elements.
*/
$.fn.removeClassSVG = function(className){
$(this).attr('class', function(index, existingClassNames) {
var re = new RegExp('\\b' + className + '\\b', 'g');
return existingClassNames.replace(re, '');
});
return this;
};
Nach dem Laden jquery.svg.js
Sie müssen diese Datei laden: http://keith-wood.name/js/jquery.svgdom.js
.
Quelle: http://keith-wood.name/svg.html#dom
Arbeitsbeispiel: http://jsfiddle.net/74RbC/99/
Fügen Sie einfach den fehlenden Prototypkonstruktor zu allen SVG-Knoten hinzu:
SVGElement.prototype.hasClass = function (className) {
return new RegExp('(\\s|^)' + className + '(\\s|$)').test(this.getAttribute('class'));
};
SVGElement.prototype.addClass = function (className) {
if (!this.hasClass(className)) {
this.setAttribute('class', this.getAttribute('class') + ' ' + className);
}
};
SVGElement.prototype.removeClass = function (className) {
var removedClass = this.getAttribute('class').replace(new RegExp('(\\s|^)' + className + '(\\s|$)', 'g'), '$2');
if (this.hasClass(className)) {
this.setAttribute('class', removedClass);
}
};
Sie können es dann auf diese Weise verwenden, ohne jQuery zu benötigen:
this.addClass('clicked');
this.removeClass('clicked');
Alle Kredite gehen an Todd Moto .
Der Beitrag jQuery 2.2 und 1.12 veröffentlicht enthält das folgende Zitat:
Während jQuery eine HTML-Bibliothek ist, waren wir uns einig, dass die Klassenunterstützung für SVG-Elemente nützlich sein könnte. Benutzer können jetzt .addClass () , . RemoveClass () , . toggleClass () und . hasClass () Methoden auf SVG. jQuery ändert jetzt das Klassenattribut und nicht die Eigenschaft className . Dadurch können die Klassenmethoden auch in allgemeinen XML-Dokumenten verwendet werden. Beachten Sie, dass viele andere Dinge mit SVG nicht funktionieren. Wir empfehlen jedoch, eine Bibliothek für SVG zu verwenden, wenn Sie etwas anderes als die Bearbeitung von Klassen benötigen.
Es testet:
Wenn Sie auf dieses kleine Quadrat klicken, ändert es seine Farbe, da das Attribut class
hinzugefügt/entfernt wird.
$("#x").click(function() {
if ( $(this).hasClass("clicked") ) {
$(this).removeClass("clicked");
} else {
$(this).addClass("clicked");
}
});
.clicked {
fill: red !important;
}
<html>
<head>
<script src="https://code.jquery.com/jquery-2.2.0.js"></script>
</head>
<body>
<svg width="80" height="80">
<rect id="x" width="80" height="80" style="fill:rgb(0,0,255)" />
</svg>
</body>
</html>
jQuery unterstützt keine Klassen von SVG-Elementen. Sie können das Element direkt $(el).get(0)
abrufen und classList
und add / remove
Verwenden. Auch hier gibt es einen Trick: Das oberste SVG-Element ist eigentlich ein normales DOM-Objekt und kann wie jedes andere Element in jQuery verwendet werden. In meinem Projekt habe ich dies erstellt, um mich um das zu kümmern, was ich brauchte, aber die Dokumentation im Mozilla Developer Network hat ein Shim, das als Alternative verwendet werden kann.
function addRemoveClass(jqEl, className, addOrRemove)
{
var classAttr = jqEl.attr('class');
if (!addOrRemove) {
classAttr = classAttr.replace(new RegExp('\\s?' + className), '');
jqEl.attr('class', classAttr);
} else {
classAttr = classAttr + (classAttr.length === 0 ? '' : ' ') + className;
jqEl.attr('class', classAttr);
}
}
Eine Alternative ist die Verwendung von D3.js als Auswahlmodul. Meine Projekte enthalten Diagramme, die damit erstellt wurden, sodass sie sich auch in meinem Anwendungsbereich befinden. D3 ändert die Klassenattribute von Vanilla DOM-Elementen und SVG-Elementen korrekt. Obwohl das Hinzufügen von D3 für genau diesen Fall wahrscheinlich übertrieben wäre.
d3.select(el).classed('myclass', true);
Hier ist mein ziemlich uneleganter, aber funktionierender Code, der sich mit den folgenden Problemen befasst (ohne Abhängigkeiten):
classList
existiert nicht für <svg>
- Elemente im IEclassName
repräsentiert nicht das class
Attribut für <svg>
Elemente im IEgetAttribute()
und setAttribute()
beschädigtWo möglich, wird classList
verwendet.
Code:
var classNameContainsClass = function(fullClassName, className) {
return !!fullClassName &&
new RegExp("(?:^|\\s)" + className + "(?:\\s|$)").test(fullClassName);
};
var hasClass = function(el, className) {
if (el.nodeType !== 1) {
return false;
}
if (typeof el.classList == "object") {
return (el.nodeType == 1) && el.classList.contains(className);
} else {
var classNameSupported = (typeof el.className == "string");
var elClass = classNameSupported ? el.className : el.getAttribute("class");
return classNameContainsClass(elClass, className);
}
};
var addClass = function(el, className) {
if (el.nodeType !== 1) {
return;
}
if (typeof el.classList == "object") {
el.classList.add(className);
} else {
var classNameSupported = (typeof el.className == "string");
var elClass = classNameSupported ?
el.className : el.getAttribute("class");
if (elClass) {
if (!classNameContainsClass(elClass, className)) {
elClass += " " + className;
}
} else {
elClass = className;
}
if (classNameSupported) {
el.className = elClass;
} else {
el.setAttribute("class", elClass);
}
}
};
var removeClass = (function() {
function replacer(matched, whiteSpaceBefore, whiteSpaceAfter) {
return (whiteSpaceBefore && whiteSpaceAfter) ? " " : "";
}
return function(el, className) {
if (el.nodeType !== 1) {
return;
}
if (typeof el.classList == "object") {
el.classList.remove(className);
} else {
var classNameSupported = (typeof el.className == "string");
var elClass = classNameSupported ?
el.className : el.getAttribute("class");
elClass = elClass.replace(new RegExp("(^|\\s)" + className + "(\\s|$)"), replacer);
if (classNameSupported) {
el.className = elClass;
} else {
el.setAttribute("class", elClass);
}
}
}; //added semicolon here
})();
Anwendungsbeispiel:
var el = document.getElementById("someId");
if (hasClass(el, "someClass")) {
removeClass(el, "someClass");
}
addClass(el, "someOtherClass");
Ich benutze Snap.svg, um eine Klasse und SVG hinzuzufügen.
var jimmy = Snap(" .jimmy ")
jimmy.addClass("exampleClass");
Eine Problemumgehung könnte darin bestehen, einem Container des svg-Elements eine Klasse hinzuzufügen:
$('.svg-container').addClass('svg-red');
.svg-red svg circle{
fill: #ED3F32;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="svg-container">
<svg height="40" width="40">
<circle cx="20" cy="20" r="20"/>
</svg>
</div>
Inspiriert von den obigen Antworten, insbesondere von Sagar Gala, habe ich dieses API erstellt. Sie können es verwenden, wenn Sie Ihre jquery-Version nicht aktualisieren möchten oder können.
Ich habe das in meinem Projekt geschrieben und es funktioniert ... wahrscheinlich;)
$.fn.addSvgClass = function(className) {
var attr
this.each(function() {
attr = $(this).attr('class')
if(attr.indexOf(className) < 0) {
$(this).attr('class', attr+' '+className+ ' ')
}
})
};
$.fn.removeSvgClass = function(className) {
var attr
this.each(function() {
attr = $(this).attr('class')
attr = attr.replace(className , ' ')
$(this).attr('class' , attr)
})
};
beispiele
$('path').addSvgClass('fillWithOrange')
$('path').removeSvgClass('fillWithOrange')