JQuery SVG, почему я не могу добавитьClass?
Я использую 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 работают вместе отлично, потому что я может нацеливать объект и запускать предупреждение при нажатии:
$(".jimmy").click(function() {
alert('Handler for .click() called.');
});
Ответы
Ответ 1
JQuery не может добавить класс в SVG.
.attr()
работает с SVG, поэтому, если вы хотите зависеть от jQuery:
// Instead of .addClass("newclass")
$("#item").attr("class", "oldclass newclass");
// Instead of .removeClass("newclass")
$("#item").attr("class", "oldclass");
И если вы не хотите зависеть от jQuery:
var element = document.getElementById("item");
// Instead of .addClass("newclass")
element.setAttribute("class", "oldclass newclass");
// Instead of .removeClass("newclass")
element.setAttribute("class", "oldclass");
Изменить 2016: прочитайте следующие два ответа.
-
element.classList.add('newclass')
работает в современных браузерах.
- JQuery 3 устраняет основную проблему.
Ответ 2
В DOM API есть element.classList, который работает как для HTML, так и для элементов SVG. Нет необходимости в jQuery SVG-плагине или даже jQuery.
$(".jimmy").click(function() {
this.classList.add("clicked");
});
Ответ 3
jQuery 3 не имеет этой проблемы
Одним из изменений, перечисленных в версиях jQuery 3.0, является:
добавьте манипуляцию класса 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>
Ответ 4
Если у вас есть динамические классы или вы не знаете, какие классы уже могут быть применены, то этот метод, на мой взгляд, лучший подход:
// addClass
$('path').attr('class', function(index, classNames) {
return classNames + ' class-name';
});
// removeClass
$('path').attr('class', function(index, classNames) {
return classNames.replace('class-name', '');
});
Ответ 5
Основываясь на приведенных выше ответах, я создал следующий 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;
};
Ответ 6
После загрузки jquery.svg.js
вы должны загрузить этот файл: http://keith-wood.name/js/jquery.svgdom.js
.
Источник: http://keith-wood.name/svg.html#dom
Рабочий пример: http://jsfiddle.net/74RbC/99/
Ответ 7
Просто добавьте отсутствующий конструктор прототипов ко всем узлам 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:
this.addClass('clicked');
this.removeClass('clicked');
Все кредиты отправляются Todd Moto.
Ответ 8
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);
Ответ 9
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>
Ответ 10
Вот мой довольно неэлегантный, но рабочий код, который касается следующих проблем (без каких-либо зависимостей):
-
classList
не существует в <svg>
элементах в IE
-
className
не представляет атрибут class
на элементах <svg>
в IE
- Старый 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");
Ответ 11
Я использую Snap.svg для добавления класса и SVG.
var jimmy = Snap(" .jimmy ")
jimmy.addClass("exampleClass");
http://snapsvg.io/docs/#Element.addClass
Ответ 12
Обходным решением может быть добавление 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>
Ответ 13
Вдохновленный ответами выше, особенно Sagar Gala, я создал этот API. Вы можете использовать его, если не хотите или не можете обновить версию jquery.
Ответ 14
Я написал это в своем проекте, и он работает... возможно;)
$.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')
Ответ 15
Или просто используйте методы 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 году рамка-палоза помогает довольно регулярно. Кроме того, если вы когда-нибудь слышали, что кто-то сравнивает DOM с сборкой, пинайте их мне.