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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8638621/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 06:50:36  来源:igfitidea点击:

jQuery SVG, why can't I addClass?

javascriptjquerycsssvgjquery-svg

提问by Don P

I am using jQuery SVG. I can't add or remove a class to an object. Anyone know my mistake?

我正在使用 jQuery SVG。我无法向对象添加或删除类。有人知道我的错误吗?

The SVG:

SVG:

<rect class="jimmy" id="p5" x="200" y="200" width="100" height="100" />

The jQuery that won't add the class:

不会添加类的 jQuery:

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

I know the SVG and jQuery are working together fine because I cantarget the object and fire an alert when it's clicked:

我知道 SVG 和 jQuery 可以很好地协同工作,因为我可以定位对象并在单击它时发出警报:

$(".jimmy").click(function() {
    alert('Handler for .click() called.');
});

回答by forresto

Edit 2016: read the next two answers.

编辑 2016:阅读接下来的两个答案。

  • JQuery 3 fixes the underlying issue
  • Vanilla JS: element.classList.add('newclass')works in modern browsers
  • JQuery 3 修复了底层问题
  • Vanilla JS:element.classList.add('newclass')适用于现代浏览器


JQuery (less than 3) can't add a class to an SVG.

JQuery(少于 3 个)无法向 SVG 添加类。

.attr()works with SVG, so if you want to depend on jQuery:

.attr()适用于 SVG,因此如果您想依赖 jQuery:

// Instead of .addClass("newclass")
$("#item").attr("class", "oldclass newclass");
// Instead of .removeClass("newclass")
$("#item").attr("class", "oldclass");

And if you don't want to depend on jQuery:

如果你不想依赖 jQuery:

var element = document.getElementById("item");
// Instead of .addClass("newclass")
element.setAttribute("class", "oldclass newclass");
// Instead of .removeClass("newclass")
element.setAttribute("class", "oldclass");

回答by Tomas Mikula

There is element.classListin the DOM API that works for both HTML and SVG elements. No need for jQuery SVG plugin or even jQuery.

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

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

回答by Alexander O'Mara

jQuery 3 does not have this problem

jQuery 3 没有这个问题

One of the changes listed on the jQuery 3.0 revisionsis:

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

add SVG class manipulation (#2199, 20aaed3)

添加SVG类的操作(#219920aaed3

One solution for this issue would be to upgrade to jQuery 3. It works great:

这个问题的一个解决方案是升级到 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>



The Problem:

问题:

The reason the jQuery class manipulation functions do not work with the SVG elements is because jQuery versions prior to 3.0 use the classNameproperty for these functions.

jQuery 类操作函数不适用于 SVG 元素的原因是因为 3.0 之前的 jQuery 版本使用className这些函数的属性。

Excerpt from jQuery attributes/classes.js:

来自 jQuery 的摘录attributes/classes.js

cur = elem.nodeType === 1 && ( elem.className ?
    ( " " + elem.className + " " ).replace( rclass, " " ) :
    " "
);

This behaves as expected for HTML elements, but for SVG elements classNameis a little different. For an SVG element, classNameis not a string, but an instance of SVGAnimatedString.

这对于 HTML 元素的行为符合预期,但对于 SVG 元素className则略有不同。对于 SVG 元素,className不是字符串,而是SVGAnimatedString.

Consider the following code:

考虑以下代码:

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>

If you run this code you will see something like the following in your developer console.

如果您运行此代码,您将在开发者控制台中看到类似以下内容。

test div
SVGAnimatedString { baseVal="test svg",  animVal="test svg"}

If we were to cast that SVGAnimatedStringobject to a string as jQuery does, we would have [object SVGAnimatedString], which is where jQuery fails.

如果我们SVGAnimatedString像 jQuery 那样将该对象强制转换为字符串,我们就会有[object SVGAnimatedString],这就是 jQuery 失败的地方。

How the jQuery SVG plugin handles this:

jQuery SVG 插件如何处理这个:

The jQuery SVG plugin works around this by patching the relevant functions to add SVG support.

jQuery SVG 插件通过修补相关函数来添加 SVG 支持来解决这个问题。

Excerpt from jQuery SVG jquery.svgdom.js:

jQuery SVG 摘录jquery.svgdom.js

function getClassNames(elem) {
    return (!$.svg.isSVGElem(elem) ? elem.className :
        (elem.className ? elem.className.baseVal : elem.getAttribute('class'))) || '';
}

This function will detect if an element is an SVG element, and if it is it will use the baseValproperty of the SVGAnimatedStringobject if available, before falling back on the classattribute.

这个函数将检测一个元素是否是一个 SVG 元素,如果是,它将在返回属性之前使用对象的baseVal属性(SVGAnimatedString如果可用)class

jQuery's historical stance on the issue:

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

jQuery currently lists this issue on their Won't Fixpage. Here is the relevant parts.

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

SVG/VML or Namespaced Elements Bugs

jQuery is primarily a library for the HTML DOM, so most problems related to SVG/VML documents or namespaced elements are out of scope. We do try to address problems that "bleed through" to HTML documents, such as events that bubble out of SVG.

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

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

Evidently jQuery considered full SVG support outside the scope of the jQuery core, and better suited for plugins.

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

回答by nav

If you have dynamic classes or don't know what classes could be already applied then this method I believe is the best approach:

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

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

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

回答by Sagar Gala

Based on above answers I created the following API

基于以上答案,我创建了以下 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;
};

回答by bennedich

After loading jquery.svg.jsyou must load this file: http://keith-wood.name/js/jquery.svgdom.js.

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

Source: http://keith-wood.name/svg.html#dom

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

Working example: http://jsfiddle.net/74RbC/99/

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

回答by Ziad

Just add the missing prototype constructor to all SVG nodes:

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

You can then use it this way without requiring jQuery:

然后你可以这样使用它而不需要 jQuery:

this.addClass('clicked');

this.removeClass('clicked');

All credit goes to Todd Moto.

所有功劳都归功于Todd Moto

回答by QueueHammer

jQuery does not support the classes of SVG elements. You can get the element directly $(el).get(0)and use classListand add / remove. There is a trick with this too in that the topmost SVG element is actually a normal DOM object and can be used like every other element in jQuery. In my project I created this to take care of what I needed but the documentation provided on the Mozilla Developer Networkhas a shim that can be used as an alternative.

jQuery 不支持 SVG 元素的类。您可以直接获取元素$(el).get(0)并使用classListand add / remove。这也有一个技巧,最顶层的 SVG 元素实际上是一个普通的 DOM 对象,可以像 jQuery 中的所有其他元素一样使用。在我的项目中,我创建了它来处理我需要的东西,但是Mozilla 开发人员网络上提供的文档有一个可以用作替代品的垫片。

example

例子

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

An alternative all tougher is to use D3.js as your selector engine instead. My projects have charts that are built with it so it's also in my app scope. D3 correctly modifies the class attributes of vanilla DOM elements and SVG elements. Though adding D3 for just this case would likely be overkill.

另一种更难的方法是使用 D3.js 作为您的选择器引擎。我的项目有用它构建的图表,所以它也在我的应用程序范围内。D3 正确修改了 vanilla DOM 元素和 SVG 元素的类属性。尽管仅在这种情况下添加 D3 可能会矫枉过正。

d3.select(el).classed('myclass', true);

回答by ROMANIA_engineer

jQuery 2.2 supports SVG class manipulation

jQuery 2.2 支持 SVG 类操作

The jQuery 2.2 and 1.12 Releasedpost includes the following quote:

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. jQuerynow 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 是一个 HTML 库,但我们同意对 SVG 元素的类支持可能很有用。用户现在可以在SVG上调用.addClass().removeClass().toggleClass().hasClass()方法。jQuery现在更改 class 属性而不是 className 属性。这也使得类方法可用于一般 XML 文档。请记住,许多其他东西不适用于 SVG,如果您需要类操作以外的任何东西,我们仍然建议使用专用于 SVG 的库。

Example using jQuery 2.2.0

使用jQuery 2.2.0 的示例

It tests:

它测试:

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

If you click on that small square, it will change its color because the classattribute is added / removed.

如果你点击那个小方块,它会改变它的颜色,因为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>

回答by Tim Down

Here is my rather inelegant but working code that deals with the following issues (without any dependencies):

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

  • classListnot existing on <svg>elements in IE
  • classNamenot representing the classattribute on <svg>elements in IE
  • Old IE's broken getAttribute()and setAttribute()implementations
  • classList不存在<svg>于 IE 中的元素上
  • className不代表IE 中元素的class属性<svg>
  • 旧 IE 的损坏getAttribute()setAttribute()实现

It uses classListwhere possible.

classList在可能的情况下使用。

Code:

代码:

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

Example usage:

用法示例:

var el = document.getElementById("someId");
if (hasClass(el, "someClass")) {
    removeClass(el, "someClass");
}
addClass(el, "someOtherClass");