J'utilise jQuery SVG. Je ne peux pas ajouter ou supprimer une classe à un objet. Quelqu'un sait mon erreur?
Le SVG:
<rect class="jimmy" id="p5" x="200" y="200" width="100" height="100" />
Le jQuery qui n'ajoutera pas la classe:
$(".jimmy").click(function() {
$(this).addClass("clicked");
});
Je sais que le SVG et jQuery fonctionnent bien parce que je peux je cible l’objet et déclenche une alerte quand on clique dessus:
$(".jimmy").click(function() {
alert('Handler for .click() called.');
});
Edit 2016: lisez les deux réponses suivantes.
element.classList.add('newclass')
fonctionne dans les navigateurs modernesJQuery (moins de 3) ne peut pas ajouter une classe à un SVG.
.attr()
fonctionne avec SVG, donc si vous voulez dépendre de jQuery:
// Instead of .addClass("newclass")
$("#item").attr("class", "oldclass newclass");
// Instead of .removeClass("newclass")
$("#item").attr("class", "oldclass");
Et si vous ne voulez pas dépendre de jQuery:
var element = document.getElementById("item");
// Instead of .addClass("newclass")
element.setAttribute("class", "oldclass newclass");
// Instead of .removeClass("newclass")
element.setAttribute("class", "oldclass");
Il y a element.classList dans l'API DOM qui fonctionne à la fois pour les éléments HTML et SVG. Pas besoin de plugin jQuery SVG ni même de jQuery.
$(".jimmy").click(function() {
this.classList.add("clicked");
});
L'un des changements répertoriés sur les révisions jQuery 3. est:
Une solution à ce problème serait de passer à jQuery 3. Cela fonctionne très bien:
_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>
_
La raison pour laquelle les fonctions de manipulation de classe jQuery ne fonctionnent pas avec les éléments SVG est due au fait que les versions antérieures à la version 3.0 utilisaient la propriété className
pour ces fonctions.
attributes/classes.js
:_cur = elem.nodeType === 1 && ( elem.className ?
( " " + elem.className + " " ).replace( rclass, " " ) :
" "
);
_
Cela se comporte comme prévu pour les éléments HTML, mais pour les éléments SVG, className
est un peu différent. Pour un élément SVG, className
n'est pas une chaîne, mais une instance de 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>
_
Si vous exécutez ce code, vous verrez quelque chose comme ce qui suit dans votre console de développement.
_test div
SVGAnimatedString { baseVal="test svg", animVal="test svg"}
_
Si nous devions transtyper cet objet SVGAnimatedString
en une chaîne comme le fait jQuery, nous aurions _[object SVGAnimatedString]
_, où jQuery échoue.
Le plug-in jQuery SVG résout ce problème en appliquant des correctifs aux fonctions appropriées pour ajouter le support SVG.
jquery.svgdom.js
:_function getClassNames(elem) {
return (!$.svg.isSVGElem(elem) ? elem.className :
(elem.className ? elem.className.baseVal : elem.getAttribute('class'))) || '';
}
_
Cette fonction détectera si un élément est un élément SVG et si c'est le cas, elle utilisera la propriété baseVal
de l'objet SVGAnimatedString
si disponible, avant de revenir à l'attribut class
.
jQuery répertorie actuellement ce problème sur sa page Won’t Fix . Voici les parties pertinentes.
Bugs SVG/VML ou Namespaced Elements
jQuery est principalement une bibliothèque pour le DOM HTML, de sorte que la plupart des problèmes liés aux documents SVG/VML ou aux éléments namespaced sont hors de portée. Nous essayons de résoudre les problèmes qui se répercutent sur les documents HTML, tels que les événements sortant du format SVG.
Évidemment, jQuery a considéré que la prise en charge complète de SVG ne faisait pas partie du noyau de jQuery et était mieux adaptée aux plugins.
Si vous avez des classes dynamiques ou ne savez pas quelles classes pourraient déjà être appliquées, cette méthode est, à mon avis, la meilleure approche:
// addClass
$('path').attr('class', function(index, classNames) {
return classNames + ' class-name';
});
// removeClass
$('path').attr('class', function(index, classNames) {
return classNames.replace('class-name', '');
});
Sur la base des réponses ci-dessus, j'ai créé l'API suivante
/*
* .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;
};
Après avoir chargé jquery.svg.js
, vous devez charger ce fichier: http://keith-wood.name/js/jquery.svgdom.js
.
Source: http://keith-wood.name/svg.html#dom
Exemple de travail: http://jsfiddle.net/74RbC/99/
Ajoutez simplement le constructeur de prototype manquant à tous les nœuds SVG:
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);
}
};
Vous pouvez ensuite l'utiliser de cette manière sans avoir besoin de jQuery:
this.addClass('clicked');
this.removeClass('clicked');
Tout le crédit va à Todd Moto .
Le jQuery 2.2 et 1.12 publiés post inclut la citation suivante:
Bien que jQuery soit une bibliothèque HTML, nous avons convenu que le support de classe pour les éléments SVG pourrait être utile. Les utilisateurs pourront désormais appeler le . AddClass () , . RemoveClass () , . toggleClass () et . hasClass () méthodes sur SVG. jQuery maintenant modifie l'attribut de classe plutôt que la propriété className . Cela rend également les méthodes de classe utilisables dans les documents XML généraux. Gardez à l'esprit que beaucoup d'autres choses ne fonctionneront pas avec SVG, et nous vous recommandons néanmoins d'utiliser une bibliothèque dédiée à SVG si vous avez besoin de quelque chose de plus que la manipulation de classe.
Il teste:
Si vous cliquez sur ce petit carré, sa couleur changera car l'attribut class
est ajouté/supprimé.
$("#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 ne prend pas en charge les classes d'éléments SVG. Vous pouvez obtenir l'élément directement $(el).get(0)
et utiliser classList
et add / remove
. Cela présente également un truc: le plus haut élément SVG est en fait un objet DOM normal et peut être utilisé comme tout autre élément de jQuery. Dans mon projet, j’ai créé ceci afin de prendre en charge ce dont j’avais besoin, mais la documentation fournie sur le Réseau de développeurs Mozilla comporte un shim qui peut être utilisé comme alternative.
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);
}
}
Une alternative plus difficile consiste à utiliser D3.js comme moteur de sélection. Mes projets ont des graphiques qui sont construits avec elle, c'est donc aussi dans la portée de mon application. D3 modifie correctement les attributs de classe des éléments Vanilla DOM et des éléments SVG. Bien que l'ajout de D3 pour ce cas seulement serait sans doute excessif.
d3.select(el).classed('myclass', true);
Voici mon code plutôt inélégant mais fonctionnel qui traite les problèmes suivants (sans aucune dépendance):
classList
non existant sur les éléments <svg>
dans IEclassName
ne représentant pas l'attribut class
sur les éléments <svg>
dans IEgetAttribute()
et setAttribute()
de l'ancien IEIl utilise classList
si possible.
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
})();
Exemple d'utilisation:
var el = document.getElementById("someId");
if (hasClass(el, "someClass")) {
removeClass(el, "someClass");
}
addClass(el, "someOtherClass");
J'utilise Snap.svg pour ajouter une classe à et SVG.
var jimmy = Snap(" .jimmy ")
jimmy.addClass("exampleClass");
Une solution de contournement pourrait être d'ajouterClass à un conteneur de l'élément svg:
$('.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>
Inspiré par les réponses ci-dessus, en particulier par Sagar Gala, j'ai créé ceci API . Vous pouvez l'utiliser si vous ne voulez pas ou ne pouvez pas mettre à jour votre version de jQuery.
Je l'ai écrit dans mon projet, et ça marche ... probablement;)
$.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)
})
};
exemples
$('path').addSvgClass('fillWithOrange')
$('path').removeSvgClass('fillWithOrange')