jQuery SVG, ¿por qué no puedo addClass?

Estoy usando jQuery SVG. No se pueden agregar o eliminar una clase a un objeto. Alguien sabe mi error?

El SVG:

<rect class="jimmy" id="p5" x="200" y="200" width="100" height="100" />

El jQuery que no se añadirá a la clase:

$(".jimmy").click(function() {
    $(this).addClass("clicked");
});

Sé el SVG y jQuery están trabajando juntos bien porque me puede objetivo el objeto y el fuego de una alerta cuando se hace clic en:

$(".jimmy").click(function() {
    alert('Handler for .click() called.');
});
Buen artículo aquí: toddmotto.com/…
Así que la pregunta de PORQUE no puedo usar el jQuery *funciones de clase sigue sin respuesta… Si puedo acceder a las propiedades de los elementos SVG a través de jQuery attr función, ¿por qué no puede el *funciones de clase también hacer esto? jQuery NO?!?
En serio, ¿alguien sabe PORQUE??
Pequeña biblioteca que añade esta funcionalidad para archivos SVG: github.com/toddmotto/lunar
El «por qué» es porque jQuery utiliza el «className» de la propiedad, que es una propiedad de cadena de elementos HTML, pero es un SVG Animados de la Cadena de elementos SVG. Que no se pueden asignar como para los elementos HTML. Por lo tanto, el código jQuery golpes tratando de asignar el valor.

OriginalEl autor Don P | 2011-12-26

12 Kommentare

  1. 407

    Edición de 2016: leer los próximos dos respuestas.

    • JQuery 3 corrige el problema subyacente
    • Vainilla JS: element.classList.add('newclass') funciona en los navegadores modernos

    JQuery (menos de 3) no se puede añadir una clase a un SVG.

    .attr() trabaja con SVG, por lo que si queremos depender de jQuery:

    //Instead of .addClass("newclass")
    $("#item").attr("class", "oldclass newclass");
    //Instead of .removeClass("newclass")
    $("#item").attr("class", "oldclass");

    Y si no queremos depender de jQuery:

    var element = document.getElementById("item");
    //Instead of .addClass("newclass")
    element.setAttribute("class", "oldclass newclass");
    //Instead of .removeClass("newclass")
    element.setAttribute("class", "oldclass");
    En apoyo a forresto sugerencia – discusscode.blogspot.en/2012/08/…
    perfecto. esta debe ser la respuesta. aunque la VERDADERA respuesta es para jquery para incluir esta opción por defecto, al menos como una opción o algo.
    .attr("class", "oldclass") (o el más complicado .setAttribute("class", "oldclass")) es realmente no es equivalente a la eliminación de newclass!
    Gran respuesta ( y v. bonito técnica ) … pero sería una idea para editar la pregunta, así que comienza por declarar que jquery no puede añadir una clase a un SVG ( si ese es el caso … como parece )?
    Sólo un apéndice: he intentado y JQuery 3 no se solucionó el problema.

    OriginalEl autor forresto

  2. 72

    Hay elemento.classList en la API del DOM que funciona tanto para HTML y elementos SVG. No hay necesidad de jQuery SVG plugin o incluso jQuery.

    $(".jimmy").click(function() {
        this.classList.add("clicked");
    });
    He probado esto, y .classList parece ser indefinido svg sub-elementos, al menos en Chrome.
    A mi me funciona en Chrome. He SVG incrustado en HTML, así que mi documento de estructura se parece a esto: <html><svg><círculo class=»jimmy» …></svg></html>
    He utilizado este para agregar la clase en un <p> SVG elemento, funciona bien en Chrome.
    Es decir no aplicar .classList y API en SVG Elementos. Consulte caniuse.com/#feat=classlist y los «problemas conocidos» de la lista. Que menciona los navegadores WebKit también.
    Y como pasa el tiempo, esta respuesta se vuelve aún más correcta (y la mejor respuesta)

    OriginalEl autor Tomas Mikula

  3. 37

    Si usted tiene clases dinámicas o no saben qué clases podría ser que ya se aplica este método, creo que es el mejor enfoque:

    //addClass
    $('path').attr('class', function(index, classNames) {
        return classNames + ' class-name';
    });
    
    //removeClass
    $('path').attr('class', function(index, classNames) {
        return classNames.replace('class-name', '');
    });
    Este fue un livesaver para mí, ya que tenía que cambiar un montón de SVG-elementos para hacer las cosas. +999 de mí 🙂
    Es difícil creer que jQuery aún podrían tener sus talones cavado en este, incluso después de 2 años y la liberación de los 2.x.x. Su revisión, nav, salvó el día para mí. El resto de estas revisiones fueron innecesariamente complejo. Gracias!

    OriginalEl autor nav

  4. 15

    Basado en respuestas anteriores he creado la siguiente API

    /*
     * .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;
    };
    usted realmente no necesita regexp aquí, la llanura de la cadena de reemplazo es mucho más rápido…
    Esto es útil, pero los algoritmos tienen problemas: 1. Si no hay ninguna clase de cadena, se obtiene ‘undedfined className’, sobre la adición de una clase. 2. Si la clase string que contiene una clase que es la superconjunto de la expresión regular, de salir de detrás de basura en la clase string. Por ejemplo, si intenta eliminar la clase «perro» y la clase string contiene ‘dogfood’, te quedará con ‘comida’ en la clase string. Aquí están algunas de las revisiones: jsfiddle.net/hellobrett/c2c2zfto
    Esta no es una solución perfecta. Reemplazar todas las palabras que contengan la clase que desea eliminar.
    Gracias @Brett. He actualizado el código.

    OriginalEl autor Sagar Gala

  5. 12

    Después de la carga jquery.svg.js debe cargar este archivo: http://keith-wood.name/js/jquery.svgdom.js.

    Fuente: http://keith-wood.name/svg.html#dom

    De trabajo ejemplo: http://jsfiddle.net/74RbC/99/

    Añadido – todavía no parece funcionar. He estado buscando a través de la documentación de jquery SVG del sitio, pero no hay una clara explicación de lo que usted necesita hacer para hacer uso de su funcionalidad extra.
    Sí, así es, se ha agregado un ejemplo de trabajo.

    OriginalEl autor bennedich

  6. 6

    Acaba de agregar la falta prototipo del constructor para todos SVG nodos:

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

    Usted puede, a continuación, utilizarlo de esta manera sin necesidad de jQuery:

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

    Todo el crédito va a Todd Moto.

    OriginalEl autor

  7. 5

    jQuery no apoyo en las clases de elementos SVG. Usted puede obtener el elemento directamente $(el).get(0) y uso classList y add /remove. Hay un truco con esta demasiado en que el primer elemento SVG es en realidad una normal objeto DOM y puede ser utilizado como cualquier otro elemento en jQuery. En mi proyecto he creado este para cuidar de lo que yo necesitaba, pero la documentación proporcionada en el Mozilla Developer Network tiene un espesor que puede ser utilizado como una alternativa.

    ejemplo

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

    Una alternativa a todos más fuertes, es el uso de D3.js como su motor de selección en su lugar. Mis proyectos se han gráficos que se construyen con ella por lo que también en mi aplicación el ámbito de aplicación. D3 modifica correctamente los atributos de la clase de vainilla elementos del DOM y SVG elementos. A pesar de la adición de D3 para este caso probablemente sería una exageración.

    d3.select(el).classed('myclass', true);
    Gracias por que d3 poco… en realidad yo ya había d3 en la página así que decidí usar que. Muy útil 🙂

    OriginalEl autor QueueHammer

  8. 3

    Aquí es mi lugar poco elegante pero código de trabajo que se ocupa de las siguientes cuestiones (sin dependencias):

    • classList no existente en <svg> elementos en IE
    • className no representa la class atributo en <svg> elementos en IE
    • Antiguas de IE roto getAttribute() y setAttribute() implementaciones

    Utiliza classList donde sea posible.

    Código:

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

    Ejemplo de uso:

    var el = document.getElementById("someId");
    if (hasClass(el, "someClass")) {
        removeClass(el, "someClass");
    }
    addClass(el, "someOtherClass");
    Hizo usted la prueba usando IE7? Porque LTE IE7 requiere strAttributeName a ser «className» al establecer, obtener, o la eliminación de un atributo de CLASE.
    Definitivamente funciona en IE 6 y 7 para regular los elementos HTML, ya que en esos navegadores que utiliza el className de la propiedad en lugar de tratar de establecer un atributo. La razón por la que «LTE IE7 requiere strAttributeName a ser «className» al establecer, obtener, o la eliminación de un atributo de CLASE» es que los navegadores tienen rota la implementación de getAttribute(x) y setAttribute(x) que simplemente obtener o establecer la propiedad con nombre x, así es más fácil y más compatible para establecer la propiedad directamente.
    OK. Yo no estaba seguro de que ya SVG no es compatible con IE 7, así que no estoy seguro de lo que se espera lograr mediante la inclusión de una <svg> elemento en una página que está diseñado para funcionar en IE 7. Para lo que vale, mi código de agregar un atributo de clase con éxito a <svg> elementos en IE 7, ya que dicho elemento se comporta como cualquier otro elemento personalizado.
    Había olvidado por completo que gracias por el recordatorio. Ill intentar conseguir mis manos en el Visor SVG de Adobe para comprobar si funciona como se pretende.

    OriginalEl autor Tim Down

  9. 2

    Yo uso el Complemento.svg para agregar una clase y SVG.

    var jimmy = Snap(" .jimmy ")
    
    jimmy.addClass("exampleClass");

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

    Mientras que este vínculo puede responder a la pregunta, es mejor incluir a las partes esenciales de la respuesta aquí y proporcionar el enlace de referencia. Enlace-sólo respuestas puede ser válido si la página enlazada cambios.
    Actualizado. Gracias

    OriginalEl autor cjohndesign

  10. 0

    Inspirado por las respuestas anteriores, especialmente por la Sagar Gala, he creado esta API. Usted puede utilizar si usted no quiere o no puede actualizar su versión de jquery.

    OriginalEl autor Stonecrusher

  11. 0

    Escribí esto en mi proyecto, y funciona… probablemente;)

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

    ejemplos

    $('path').addSvgClass('fillWithOrange')
    $('path').removeSvgClass('fillWithOrange')

    OriginalEl autor Dariusz Majchrzak

  12. -1

    O simplemente el uso de la vieja escuela de métodos de DOM cuando JQ tiene un mono en el centro en algún lugar.

    var myElement = $('#my_element')[0];
    var myElClass = myElement.getAttribute('class').split(/\s+/g);
    //splits class into an array based on 1+ white space characters
    
    myElClass.push('new_class');
    
    myElement.setAttribute('class', myElClass.join(' '));
    
    //$(myElement) to return to JQ wrapper-land

    Aprender el DOM personas. Incluso en 2016 marco-palooza ayuda bastante regularidad. También, si alguna vez escuchar a alguien comparar el DOM a la asamblea, tiro de ellos para mí.

    OriginalEl autor Erik Reppen

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea