jQuery SVG, почему я не могу добавить класс?
Я использую jQuery 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.');
});
15 ответов:
Edit 2016: прочитайте следующие два ответа.
- JQuery 3 исправляет основную проблему
- Vanilla JS:
element.classList.add('newclass')работает в современных браузерах
JQuery (менее 3) не может добавить класс в 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");
здесь элемент.classList в DOM API, который работает как для HTML, так и для SVG-элементов. Нет необходимости в плагине jQuery SVG или даже jQuery.
$(".jimmy").click(function() { this.classList.add("clicked"); });
jQuery 3 не имеет этой проблемы
одно из изменений, перечисленных на версии jQuery 3.0 - это:
одним из решений этой проблемы было бы обновление до 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свойства этих функций.отрывок из jQuery
attributes/classes.js:cur = elem.nodeType === 1 && ( elem.className ? ( " " + elem.className + " " ).replace( rclass, " " ) : " " );это ведет себя так, как ожидалось для HTML-элементов, но для SVG-элементов
classNameнемного отличается. Для элемента SVG,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.
отрывок из jQuery SVG
jquery.svgdom.js:function getClassNames(elem) { return (!$.svg.isSVGElem(elem) ? elem.className : (elem.className ? elem.className.baseVal : elem.getAttribute('class'))) || ''; }эта функция определит, является ли элемент элементом SVG, и если это так, он будет использовать
baseValсвойстваSVGAnimatedStringобъект, если он доступен, прежде чем вернуться на .историческая позиция jQuery по этому вопросу:
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'), ''); if (this.hasClass(className)) { this.setAttribute('class', removedClass); } };вы можете использовать его таким образом, не требуя jQuery:
this.addClass('clicked'); this.removeClass('clicked');все Тодд Мото.
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 корректно изменяет атрибуты классов элементов vanilla DOM и SVG. Хотя добавление D3 только для этого случая, вероятно, будет излишним.
d3.select(el).classed('myclass', true);
jQuery 2.2 поддерживает управление классом SVG
The jQuery 2.2 и 1.12 выпущен сообщение включает в себя следующую цитату:
хотя jQuery является библиотекой HTML, мы согласились, что поддержка классов для элементов SVG может быть полезной. Теперь пользователи смогут вызывать .addClass (),.removeClass(),.toggleClass() и .hasClass() методы на SVG. jQuery теперь изменяет атрибут класса, а не свойство className. Это также делает методы класса пригодными для использования в общих XML-документах. Имейте в виду, что многие другие вещи не будут работать с SVG, и мы по-прежнему рекомендуем использовать библиотеку, посвященную SVG, если вам нужно что-то помимо манипуляций с классами.
пример использования jQuery 2.2.0
это тесты:
- .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>элементы в IEclassNameне представляющей на<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");
Я использую оснастку.svg для добавления класса В и SVG.
var jimmy = Snap(" .jimmy ") jimmy.addClass("exampleClass");
одним из обходных путей может быть добавление класса в контейнер элемента 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 с assembly, пните их для меня.
Comments