jQuery SVG,为什么我无法添加Class?

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

4
这里有一篇好的文章:http://toddmotto.com/hacking-svg-traversing-with-ease-addclass-removeclass-toggleclass-functions/ 文章介绍了如何使用 addClass、removeClass 和 toggleClass 函数轻松遍历 SVG(可缩放矢量图形),并对其进行修改。阅读本文可以帮助您更好地掌握 SVG 的实际应用。 - Kris
8
为什么我不能使用 jQuery 的类函数仍然没有得到解答... 如果我可以通过 jQuery 的 attr 函数访问 SVG 元素的属性,为什么类函数也不能这样做?难道是 jQuery 失败了吗? - Ryan Griggs
2
真的,有人知道为什么吗? - Ben Wilde
一个小型的库,可以为SVG文件添加此功能:https://github.com/toddmotto/lunar - Chuck Le Butt
6
"为什么"是因为jQuery使用了"className"属性,它是HTML元素的字符串属性,但对于SVG元素来说,它是一个SVG动画字符串。这意味着它不能像HTML元素那样被赋值。因此,jQuery代码在尝试分配该值时会崩溃。 - Jon Watte
根据 https://dev59.com/-Goy5IYBdhLWcg3wUcRL#34698009 的回答,正确的做法是:升级到 jQuery 1.12.0、2.2.0 或 3.0 版本或更高版本。 - Ian Kemp
15个回答

3
以下是我相当不雅观但可用的代码,解决了以下问题(没有任何依赖):
- IE中元素上不存在classList - IE中className不表示元素上的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");

你用IE7测试过吗?因为在LTE IE7中,设置、获取或删除CLASS属性时,_需要将strAttributeName设置为“className”_。 - Knu
@Knu:对于常规的HTML元素,在IE 6和7中它绝对有效,因为在这些浏览器中它使用className属性而不是尝试设置属性。 "LTE IE7要求在设置、获取或删除CLASS属性时strAttributeName必须为“className”的原因是这些浏览器有一个破损的实现getAttribute(x)setAttribute(x)只是获取或设置名称为x的属性,所以直接设置属性更容易和更兼容。 - Tim Down
@Knu:好的,我不确定因为IE 7不支持SVG,所以我不知道您希望通过在设计为在IE 7中工作的页面中包含<svg>元素来实现什么。值得一提的是,我的代码确实成功地向<svg>元素添加了一个类属性,因为这样的元素表现得像任何其他自定义元素。 - Tim Down
完全忘记了,谢谢提醒。我会尝试获取Adobe SVG Viewer来检查它是否按预期工作。 - Knu

1

一种解决方法是向SVG元素的容器添加addClass:

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


1

我在我的项目中写了这个,它应该可以正常工作...也许;)

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

0
受上面的答案启发,特别是Sagar Gala的回答,我创建了这个API。如果您不想或无法升级您的jquery版本,可以使用它。

-1

或者在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比作汇编语言,替我踢他们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接