jQuery SVG,为什么我不能添加类?

IT技术 javascript jquery css svg jquery-svg
2021-02-08 16:51:22

我正在使用 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.');
});
6个回答

编辑 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");
完美的。这应该是答案。虽然真正的答案是 jquery 默认包含这个,至少作为一个设置或其他东西。
2021-03-12 16:51:22
2021-03-23 16:51:22
只是一个附录:我尝试过,但 JQuery 3 没有解决这个问题。
2021-03-25 16:51:22
.attr("class", "oldclass")(或者更麻烦的.setAttribute("class", "oldclass"))真的不等于去掉newclass
2021-04-07 16:51:22
很好的答案(和 v.nice 技术)......但是编辑问题以便它首先声明 jquery 无法向 SVG 添加一个类(如果是这样的话......看起来)?
2021-04-09 16:51:22

element.classList的DOM API,用于HTML和SVG元素的作品。不需要 jQuery SVG 插件甚至 jQuery。

$(".jimmy").click(function() {
    this.classList.add("clicked");
});
IE 没有在 SVG 元素上实现 .classList 和 API。请参阅caniuse.com/#feat=classlist和“已知问题”列表。这也提到了 WebKit 浏览器。
2021-03-12 16:51:22
我用它在 <g> SVG 元素中添加类,在 Chrome 中工作正常。
2021-03-13 16:51:22
我对此进行了测试,至少在 Chrome 中,svg 子元素的 .classList 似乎未定义。
2021-03-20 16:51:22
随着时间的推移,这个答案变得更加正确(也是最佳答案)
2021-03-25 16:51:22
在 Chrome 中为我工作。我在 HTML 中嵌入了 SVG,所以我的文档结构如下所示:<html><svg><circle class="jimmy" ...></svg></html>
2021-03-28 16:51:22

jQuery 3 没有这个问题

jQuery 3.0 修订版中列出的更改之一是:

添加SVG类的操作(#219920aaed3

这个问题的一个解决方案是升级到 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 元素的原因是因为 3.0 之前的 jQuery 版本使用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如果可用)class

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

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

SVG/VML 或命名空间元素错误

jQuery 主要是用于 HTML DOM 的库,因此与 SVG/VML 文档或命名空间元素相关的大多数问题都超出了范围。我们确实尝试解决“渗透”到 HTML 文档的问题,例如从 SVG 中冒出的事件。

显然 jQuery 考虑了 jQuery 核心范围之外的完整 SVG 支持,并且更适合插件。

如果您有动态类或不知道可以应用哪些类,那么我认为这种方法是最好的方法:

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

// removeClass
$('path').attr('class', function(index, classNames) {
    return classNames.replace('class-name', '');
});
很难相信即使在 2 年和 2.xx 发布之后,jQuery 仍然会紧追不舍。您的修复,导航,为我节省了一天。这些修复的其余部分不必要地复杂。谢谢!
2021-04-03 16:51:22
这对我来说是一个救星,因为我需要更改很多 SVG 元素才能完成任务。来自我的 +999 :)
2021-04-04 16:51:22

基于以上答案,我创建了以下 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;
};
这不是一个完美的解决方案。它替换包含您要删除的类的所有单词。
2021-03-25 16:51:22
这很有帮助,但算法存在问题: 1. 如果没有现有的类字符串,则在添加类时会得到“未定义的类名”。2. 如果类字符串包含作为正则表达式超集的类,则在类字符串中留下垃圾。例如,如果您尝试删除类 'dog' 并且类字符串包含 'dogfood',您将在类字符串中留下 'food'。以下是一些修复:jsfiddle.net/hellobrett/c2c2zfto
2021-03-26 16:51:22