jQuery SVG, why can't I addClass?

前端 未结 15 1827
失恋的感觉
失恋的感觉 2020-11-22 02:25

I am using jQuery SVG. I can\'t add or remove a class to an object. Anyone know my mistake?

The SVG:



        
相关标签:
15条回答
  • 2020-11-22 02:42

    There is element.classList in the DOM API that works for both HTML and SVG elements. No need for jQuery SVG plugin or even jQuery.

    $(".jimmy").click(function() {
        this.classList.add("clicked");
    });
    
    0 讨论(0)
  • 2020-11-22 02:42

    One workaround could be to addClass to a container of the svg element:

    $('.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>

    0 讨论(0)
  • 2020-11-22 02:44

    jQuery 3 does not have this problem

    One of the changes listed on the jQuery 3.0 revisions is:

    add SVG class manipulation (#2199, 20aaed3)

    One solution for this issue would be to upgrade to jQuery 3. It works great:

    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>


    The Problem:

    The reason the jQuery class manipulation functions do not work with the SVG elements is because jQuery versions prior to 3.0 use the className property for these functions.

    Excerpt from jQuery attributes/classes.js:

    cur = elem.nodeType === 1 && ( elem.className ?
        ( " " + elem.className + " " ).replace( rclass, " " ) :
        " "
    );
    

    This behaves as expected for HTML elements, but for SVG elements className is a little different. For an SVG element, className is not a string, but an instance of SVGAnimatedString.

    Consider the following 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>

    If you run this code you will see something like the following in your developer console.

    test div
    SVGAnimatedString { baseVal="test svg",  animVal="test svg"}
    

    If we were to cast that SVGAnimatedString object to a string as jQuery does, we would have [object SVGAnimatedString], which is where jQuery fails.

    How the jQuery SVG plugin handles this:

    The jQuery SVG plugin works around this by patching the relevant functions to add SVG support.

    Excerpt from jQuery SVG jquery.svgdom.js:

    function getClassNames(elem) {
        return (!$.svg.isSVGElem(elem) ? elem.className :
            (elem.className ? elem.className.baseVal : elem.getAttribute('class'))) || '';
    }
    

    This function will detect if an element is an SVG element, and if it is it will use the baseVal property of the SVGAnimatedString object if available, before falling back on the class attribute.

    jQuery's historical stance on the issue:

    jQuery currently lists this issue on their Won’t Fix page. Here is the relevant parts.

    SVG/VML or Namespaced Elements Bugs

    jQuery is primarily a library for the HTML DOM, so most problems related to SVG/VML documents or namespaced elements are out of scope. We do try to address problems that "bleed through" to HTML documents, such as events that bubble out of SVG.

    Evidently jQuery considered full SVG support outside the scope of the jQuery core, and better suited for plugins.

    0 讨论(0)
  • 2020-11-22 02:46

    Just add the missing prototype constructor to all SVG nodes:

    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);
      }
    };
    

    You can then use it this way without requiring jQuery:

    this.addClass('clicked');
    
    this.removeClass('clicked');
    

    All credit goes to Todd Moto.

    0 讨论(0)
  • 2020-11-22 02:49

    I wrote this in my project, and it works... probably;)

    $.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)
        })
    };    
    

    examples

    $('path').addSvgClass('fillWithOrange')
    $('path').removeSvgClass('fillWithOrange')
    
    0 讨论(0)
  • 2020-11-22 02:52

    jQuery 2.2 supports SVG class manipulation

    The jQuery 2.2 and 1.12 Released post includes the following quote:

    While jQuery is a HTML library, we agreed that class support for SVG elements could be useful. Users will now be able to call the .addClass(), .removeClass(), .toggleClass(), and .hasClass() methods on SVG. jQuery now changes the class attribute rather than the className property. This also makes the class methods usable in general XML documents. Keep in mind that many other things will not work with SVG, and we still recommend using a library dedicated to SVG if you need anything beyond class manipulation.

    Example using jQuery 2.2.0

    It tests:

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

    If you click on that small square, it will change its color because the class attribute is added / removed.

    $("#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>

    0 讨论(0)
提交回复
热议问题