Я использую jQuery SVG. Я не могу добавить или удалить класс для объекта. Кто-нибудь знает мою ошибку?

SVG:

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

JQuery, который не добавляет класс:

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

Я знаю, что SVG и jQuery отлично работают вместе, потому что я может нацеливаюсь на объект и запускаю оповещение при нажатии: JQuery 3 устраняет основную проблему

$(".jimmy").click(function() {
    alert('Handler for .click() called.');
});

Изменить 2016: прочитайте следующие два ответа.

  • Vanilla JS:
  • работает в современных браузерах element.classList.add('newclass') JQuery (менее 3) не может добавить класс в SVG.

работает с SVG, поэтому если вы хотите зависеть от jQuery:

.attr() И если вы не хотите зависеть от jQuery:

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

В DOM API есть

var element = document.getElementById("item");
// Instead of .addClass("newclass")
element.setAttribute("class", "oldclass newclass");
// Instead of .removeClass("newclass")
element.setAttribute("class", "oldclass");

element.classList , который работает как для элементов HTML, так и SVG. Нет необходимости в плагине jQuery SVG или даже jQuery. jQuery 3 не имеет этой проблемы

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

:

, являются буквы и цифры. Чтобы разрешить (но не требовать) специальные символы, вы должны использовать что-то вроде: Он работает, обнаруживая изменение в добавить манипуляции с классом SVG (

# 2199 20aaed3 , Одним из решений этой проблемы будет обновление до jQuery 3. Он прекрасно работает: С чем вы столкнулись

Проблема:

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>

Причина, по которой функции манипулирования классами jQuery не работают с элементами SVG, заключается в том, что версии jQuery до 3.0 используют свойство

для этих функций. className Это ведет себя так, как и ожидалось для элементов HTML, но для элементов SVG

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

немного отличается. Для элемента SVG className не является строкой, а является экземпляром className Рассмотрим следующий код: 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>

Если вы запустите этот код, вы увидите что-то вроде следующего в консоли разработчика.

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

Если бы мы приводили этот объект SVGAnimatedString к строке, как это делает jQuery, у нас было бы [object SVGAnimatedString], и именно здесь jQuery завершается сбоем.

Как плагин jQuery SVG справляется с этим:

Плагин jQuery SVG работает вокруг этого, исправляя соответствующие функции для добавления поддержки SVG.

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

Эта функция обнаружит, является ли элемент элементом SVG, и если это так, то будет использовать объект baseVal объекта SVGAnimatedString, если он доступен, перед тем как вернуться к атрибуту class.

Историческая позиция jQuery по этому вопросу:

jQuery в настоящее время перечисляет эту проблему на своей странице Won’t Fix . Вот соответствующие части.

Ошибки SVG / VML или элементов пространства имен

jQuery — это, прежде всего, библиотека для HTML DOM, поэтому большинство проблем, связанных с документами SVG / VML или элементами пространства имен, находятся вне области видимости. Мы стараемся решать проблемы, которые «просачиваются» в документы HTML, такие как события, которые возникают из SVG.

Очевидно, jQuery считал полную поддержку SVG вне области действия ядра jQuery и лучше подходил для плагинов.

Если у вас есть динамические классы или вы не знаете, какие классы уже могут быть применены, то этот метод, я считаю, является лучшим подходом:

// addClass
$('path').attr('class', function(index, classNames) {
    return classNames   ' class-name';
});

// removeClass
$('path').attr('class', function(index, classNames) {
    return classNames.replace('class-name', '');
});

На основе приведенных выше ответов я создал следующий 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;
};

После загрузки jquery.svg.js вы должен загрузить этот файл: http://keith-wood.name/js/jquery.svgdom.js Глядя на вывод

Источник: http://keith-wood.name/svg.html # dom

Рабочий пример: http://jsfiddle.net/74RbC/99/

Просто добавьте недостающие Конструктор прототипа для всех узлов 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);
  }
};

Затем вы можете использовать его таким образом, не требуя jQuery: {* } Я не уверен, может ли последняя строка быть преобразована в $ (‘# mySelect’). Html (output.join (»)), потому что я не знаю внутренности jQuery (возможно, она делает некоторые парсинг в методе html ())

this.addClass('clicked');

this.removeClass('clicked');

Весь кредит идет на Todd Moto Глядя на вывод

jQuery не поддерживает классы элементов SVG. Вы можете получить элемент напрямую $(el).get(0) и использовать classList и add / remove. С этим тоже есть хитрость в том, что верхний элемент SVG на самом деле является обычным объектом DOM и может использоваться как любой другой элемент в jQuery. В моем проекте я создал это, чтобы позаботиться о том, что мне нужно, но документация, предоставленная на Mozilla Developer Network имеет прокладку, которую можно использовать в качестве альтернативы. { *} объект, так что его можно удалить позже. Оператор

Пример

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

альтернативе, гораздо сложнее — вместо этого использовать D3.js в качестве механизма выбора. Мои проекты имеют графики, которые построены с его помощью, так что это также входит в сферу моего приложения. D3 правильно изменяет атрибуты класса ванильных элементов DOM и SVG. Хотя добавление D3 только для этого случая, вероятно, будет излишним.

d3.select(el).classed('myclass', true);

jQuery 2.2 поддерживает манипуляции с классами SVG

Переменная jQuery 2.2 и 1.12 Выпущенная публикация содержит следующую цитату:

Хотя jQuery — это библиотека HTML, мы согласились, что поддержка классов для элементов SVG может оказаться полезной. Теперь пользователи смогут вызывать методы . AddClass () , . RemoveClass () , . ToggleClass () и . HasClass () в SVG. jQuery сейчас изменяет атрибут класса, а не свойство className . Это также делает методы класса пригодными для использования в общих документах XML. Имейте в виду, что многие другие вещи не будут работать с SVG, и мы по-прежнему рекомендуем использовать библиотеку, посвященную SVG, если вам нужно что-то кроме манипуляций с классами.

Он проверяет:

  • . AddClass ()
  • . RemoveClass ()
  • . HasClass ()

Если вы нажмете на этот маленький квадрат, он изменит свой цвет, потому что атрибут class добавлен / удален.

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

Вот мой довольно не элегантный, но работающий код, который решает следующие проблемы (без каких-либо зависимостей):

  • classList не существует в <svg> Но,
  • className и не представляет атрибута class в <svg> Но,
  • старых реализациях IE, нарушенных getAttribute() и setAttribute() реализации

Он использует classList где возможно.

потому что это не итератор, и

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

Пример использования:

var el = document.getElementById("someId");
if (hasClass(el, "someClass")) {
    removeClass(el, "someClass");
}
addClass(el, "someOtherClass");

Я использую Snap.svg, чтобы добавить класс и SVG.

var jimmy = Snap(" .jimmy ")

jimmy.addClass("exampleClass");

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

Одним из обходных путей может быть добавление класса в контейнер элемента 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>

Вдохновленный ответами выше, особенно Сагар Гала, я создал этот API . Вы можете использовать его, если вы не хотите или не можете обновить версию JQuery.

Я написал это в своем проекте, и он работает … вероятно, ;)

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

Примеры

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

Или просто используйте методы DOM старой школы, когда у JQ где-то посередине есть обезьяна.

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

Изучите людей из DOM. Даже в рамках 2016-palooza это помогает довольно регулярно. Кроме того, если вы когда-нибудь слышали, чтобы кто-нибудь сравнил DOM со сборкой, пните их для меня.