我使用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.');
});

加载jquery.svg.js后,必须加载这个文件:http://keith-wood.name/js/jquery.svgdom.js。

来源:http://keith-wood.name/svg.html dom

工作示例:http://jsfiddle.net/74RbC/99/


编辑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");

有元素。用于HTML和SVG元素的DOM API中的classList。不需要jQuery SVG插件,甚至jQuery。

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

jQuery不支持SVG元素的类。您可以直接获取元素$(el).get(0),并使用classList和添加/删除。这也有一个技巧,最上面的SVG元素实际上是一个普通的DOM对象,可以像jQuery中的其他元素一样使用。在我的项目中,我创建了这个来照顾我需要的东西,但Mozilla开发者网络上提供的文档有一个垫片,可以用作替代方案。

例子

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

如果你有动态类或者不知道什么类可以被应用,那么我认为这个方法是最好的方法:

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

只需将缺失的原型构造函数添加到所有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');

所有功劳都归功于托德·莫托。


这里是我的相当不优雅,但工作的代码,处理以下问题(没有任何依赖):

IE中<svg>元素上不存在classList className不代表IE中<svg>元素上的class属性 旧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");

jQuery 3没有这个问题

jQuery 3.0版本中列出的一个变化是:

添加SVG类操作(#2199,20aaed3)

这个问题的一个解决方案是升级到jQuery 3。它很有效:

Var翻转= true; setInterval(函数(){ //可以使用toggleClass,但要演示addClass。 If(翻转){ $ (svg圆).addClass(“绿色”); } 其他{ $ (svg圆).removeClass(“绿色”); } 翻转= ! }, 1000); SVG圆{ 填充:红色; 中风:黑色; 笔划宽度:5; } svg圆。绿色{ 填充:绿色; } < script src = " https://code.jquery.com/jquery-3.0.0.min.js " > < /脚本> 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 { 宽度:200 px; 高度:50 px; 背景:蓝色; } <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元素,如果是,它将使用SVGAnimatedString对象的baseVal属性(如果可用),然后返回到class属性。

jQuery在这个问题上的历史立场:

jQuery目前在Won 't Fix页面上列出了这个问题。以下是相关部分。

SVG/VML或命名空间元素bug jQuery主要是HTML DOM的库,因此大多数与SVG/VML文档或名称空间元素相关的问题都不在讨论范围之内。我们确实尝试解决“渗透”到HTML文档的问题,比如从SVG冒出来的事件。

显然,jQuery认为完全支持SVG超出了jQuery核心的范围,更适合插件。


我使用Snap.svg向SVG添加一个类。

var jimmy = Snap(" .jimmy ")

jimmy.addClass("exampleClass");

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


jQuery 2.2支持SVG类操作

jQuery 2.2和1.12发布的帖子包括以下引用:

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.

jQuery 2.2.0示例

它测试:

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

如果你点击那个小方块,它会改变它的颜色,因为class属性被添加/删除了。

$ (" # x”).click(函数(){ if ($(this).hasClass("clicked")) { (美元).removeClass(“点击”); }其他{ (美元).addClass(“点击”); } }); .clicked { 填充:红色!重要; } < html > < >头 < script src = " https://code.jquery.com/jquery-2.2.0.js " > < /脚本> > < /头 身体< > <svg width="80" height="80"> <rect id="x" width="80" height="80" style="fill:rgb(0,0,255)"/> < / svg > 身体< / > < / html >


受到上述答案的启发,尤其是Sagar Gala,我创建了这个API。如果你不想或不能升级jquery版本,你可以使用它。


一个解决方法是将class添加到svg元素的容器中:

$ (' .svg-container ') .addClass(“svg-red”); . SVG -红色SVG圆圈{ 填充:# ED3F32; } < script src = " https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js " > < /脚本> < div class = " svg-container”> <svg height="40" width="40"> <circle cx="20" cy="20" r="20"/> < / svg > < / div >


或者,当JQ在某个地方出现问题时,只使用老派的DOM方法。

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与汇编进行比较,请替我踢他们一脚。


我在我的项目中写了这个,它很有效……可能,)

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