jQuery SVG,为什么我不能addClass?

Don*_*n P 283 javascript css jquery svg jquery-svg

我正在使用jQuery SVG.我无法在对象中添加或删除类.谁知道我的错误?

SVG:

<rect class="jimmy" id="p5" x="200" y="200" width="100" height="100" />
Run Code Online (Sandbox Code Playgroud)

不会添加类的jQuery:

$(".jimmy").click(function() {
    $(this).addClass("clicked");
});
Run Code Online (Sandbox Code Playgroud)

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

$(".jimmy").click(function() {
    alert('Handler for .click() called.');
});
Run Code Online (Sandbox Code Playgroud)

for*_*sto 424

编辑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");
Run Code Online (Sandbox Code Playgroud)

如果你不想依赖jQuery:

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

  • `.attr("class","oldclass")`(或者更麻烦的`.setAttribute("class","oldclass")`)实际上并不等同于删除`newclass`! (2认同)

Tom*_*ula 76

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

$(".jimmy").click(function() {
    this.classList.add("clicked");
});
Run Code Online (Sandbox Code Playgroud)

  • IE没有在SVG Elements上实现.classList和API.请参阅http://caniuse.com/#feat=classlist和"已知问题"列表.这也提到了WebKit浏览器. (20认同)
  • 随着时间的推移,这个答案变得更加正确*(最好的答案) (9认同)
  • 我对此进行了测试,并且.classList对于svg子元素似乎未定义,至少在Chrome中是这样. (3认同)
  • 在Chrome中适用于我.我有嵌入HTML的SVG,所以我的文档结构如下所示:<html> <svg> <circle class ="jimmy"...> </ svg> </ html> (3认同)

Ale*_*ara 69

jQuery 3没有这个问题

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

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

这个问题的一个解决方案是升级到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);
Run Code Online (Sandbox Code Playgroud)
svg circle {
    fill: red;
    stroke: black;
    stroke-width: 5;
}
svg circle.green {
    fill: green;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>

<svg>
    <circle cx="50" cy="50" r="25" />
</svg>
Run Code Online (Sandbox Code Playgroud)


问题:

jQuery类操作函数不能与SVG元素一起使用的原因是因为3.0之前的jQuery版本使用className这些函数的属性.

摘自jQuery attributes/classes.js:

cur = elem.nodeType === 1 && ( elem.className ?
    ( " " + elem.className + " " ).replace( rclass, " " ) :
    " "
);
Run Code Online (Sandbox Code Playgroud)

这与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);
Run Code Online (Sandbox Code Playgroud)
#test-div {
    width: 200px;
    height: 50px;
    background: blue;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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

test div
SVGAnimatedString { baseVal="test svg",  animVal="test svg"}
Run Code Online (Sandbox Code Playgroud)

如果我们要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'))) || '';
}
Run Code Online (Sandbox Code Playgroud)

此函数将检测元素是否为SVG元素,如果可用,它将在回退到属性之前使用对象的baseVal属性(SVGAnimatedString如果可用)class.

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

jQuery目前在他们的Will not Fix页面上列出了这个问题.这是相关部分.

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

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

显然jQuery认为在jQuery核心范围之外的完整SVG支持,更适合插件.


nav*_*nav 38

如果您有动态类或不知道哪些类已经应用,那么我相信这种方法是最好的方法:

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

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


Sag*_*ala 17

基于以上答案,我创建了以下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;
};
Run Code Online (Sandbox Code Playgroud)

  • 这很有用,但算法存在问题:1.如果没有现有的类字符串,则在添加类时会得到"未定义的className".2.如果类字符串包含一个类,它是正则表达式的超集,则在类字符串中留下垃圾.例如,如果您尝试删除类'dog'并且类字符串包含'dogfood',那么您将在类字符串中留下'food'.以下是一些修复:https://jsfiddle.net/hellobrett/c2c2zfto/ (3认同)
  • 你真的不需要regexp这里,普通的字符串替换要快得多...... (2认同)

ben*_*ich 13

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

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

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


Zia*_*iad 7

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

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

this.addClass('clicked');

this.removeClass('clicked');
Run Code Online (Sandbox Code Playgroud)

所有功劳都归功于Todd Moto.


Que*_*mer 5

jQuery不支持SVG元素的类.您可以直接获取元素$(el).get(0)并使用classListadd / remove.这也是一个技巧,因为最顶层的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);
  }
}
Run Code Online (Sandbox Code Playgroud)

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

d3.select(el).classed('myclass', true);
Run Code Online (Sandbox Code Playgroud)


ROM*_*eer 5

jQuery 2.2支持SVG类操作

jQuery的2.2和1.12发布后包括以下报价:

虽然jQuery是一个HTML库,但我们同意对SVG元素的类支持可能很有用.现在,用户将能够调用.addClass() ,.removeClass() ,.toggleClass() ,和.hasClass() SVG的方法.jQuery现在更改了class属性而不是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");
    }
});
Run Code Online (Sandbox Code Playgroud)
.clicked {
    fill: red !important;  
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)