webentwicklung-frage-antwort-db.com.de

jQuery SVG, warum kann ich keine Klasse hinzufügen?

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.');
});
281
Don P

Edit 2016: Lies die nächsten beiden Antworten.

  • JQuery 3 behebt das zugrunde liegende Problem
  • Vanilla JS: element.classList.add('newclass') funktioniert in modernen Browsern

JQuery (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");
420
forresto

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");
});
75
Tomas Mikula

jQuery 3 hat dieses Problem nicht

Eine der Änderungen in der jQuery 3.0-Revision ist:

manipulation der SVG-Klasse hinzufügen ( # 2199 , 20aaed3 )

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>

Das Problem:

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.

Auszug aus jQuery 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 .

Betrachten Sie den folgenden Code:

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.

Wie das jQuery SVG Plugin damit umgeht:

Das jQuery-SVG-Plugin umgeht dies, indem die relevanten Funktionen gepatcht werden, um SVG-Unterstützung hinzuzufügen.

Auszug aus jQuery SVG 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.

die historische Haltung von jQuery zu diesem Thema:

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.

69

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', '');
});
38
nav

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;
};
16
Sagar Gala

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/

13
bennedich

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 .

7
Ziad

jQuery 2.2 unterstützt die Bearbeitung von SVG-Klassen

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.

Beispiel mit jQuery 2.2.

Es testet:

  • . addClass ()
  • . removeClass ()
  • . hasClass ()

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>
5

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.

Beispiel

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);
5
QueueHammer

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 IE
  • className repräsentiert nicht das class Attribut für <svg> Elemente im IE
  • Alte IEs haben die Implementierungen getAttribute() und setAttribute() beschädigt

Wo 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");
3
Tim Down

Ich benutze Snap.svg, um eine Klasse und SVG hinzuzufügen.

var jimmy = Snap(" .jimmy ")

jimmy.addClass("exampleClass");

http://snapsvg.io/docs/#Element.addClass

2
cjohndesign

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>
1
claytronicon

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.

0
Stonecrusher

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')
0