【问题标题】:jQuery .hasClass() method fails for SVG elementsSVG 元素的 jQuery .hasClass() 方法失败
【发布时间】:2023-03-20 05:40:01
【问题描述】:

我有一组带有 nodelink 类的 SVG 元素。我的程序应该在悬停在任何 SVG 元素上时检测元素是否具有 node 类或 link 类。但是,由于某种原因,.hasClass() 似乎不起作用:

$(".node").hover(function(evt){
    console.log($(this).attr("class")); //returns "node"
    console.log($(this).hasClass('node')); //returns false
}, function(){console.log("Done");});

所以我悬停的元素有 node 类,jQuery 也检测到这一点,如 console.log($(this).attr("class")); 所示,但由于某种原因,实际的 .hasClass() 失败了。为什么是这样?是否因为 SVG 而失败?

【问题讨论】:

  • 只是一个旁注,你最后错过了); :) 和seems to work for me
  • SVG 中的元素并不是真正的 HTML,因此这些元素中缺少属性,这就是获取属性有效的原因,但使用可能检查 className 属性的 hasClass 不起作用。
  • 其实不太一样,但只要其他类都不包含字符串“node”就可以了。
  • 请记住,在使用 SVG 时,元素没有 className、innerHTML 等内容,因此并非 jQuery 中的所有内容都适用于这些元素。
  • jQuery 2.2.0 修复了这个问题 - 你可以在这里看到我的帖子:stackoverflow.com/a/34698009/3885376 包含一些细节 + 一个小例子,现在是 hasClass()addClass()removeClass() 工作。

标签: javascript jquery html css svg


【解决方案1】:

这是针对之前 jquery 3.x.x 版本的 addClass、removeClass、hasClass jquery 方法的 hack。

$.fn.extend({
    addSVGClass: function (cls) {
        return this.each(function () {
            var classList = $(this).attr('class');
            if (classList) {
                var classListArr = classList.split(" ");
                if (classListArr.indexOf(cls) === -1) {
                    classListArr.push(cls);
                    classList = classListArr.join(" ").trim();
                    $(this).attr('class', classList);
                }
            } else {
                $(this).attr('class', cls);
            }
        });
    },
    removeSVGClass: function (cls) {
        return this.each(function () {
            var classList = $(this).attr('class');
            if (classList) {
                var classListArr = classList.split(" ");
                if (classListArr.indexOf(cls) !== -1) {
                    delete classListArr[classListArr.indexOf(cls)];
                    classList = classListArr.join(" ").trim();
                    $(this).attr('class', classList);
                }
            }

        });
    },
    hasSVGClass: function (cls) {
        var el = this[0];
        var classList = $(el).attr('class');
        if (classList) {
            var classListArr = classList.split(" ");
            if (classListArr.indexOf(cls) !== -1) {
                return true;

            } else {
                return false;
            }
        }
        return false;
    }
});

用法:

$('.svg-element').addSVGClass('selected');

【讨论】:

    【解决方案2】:

    这不是有史以来最快的选择,但它是一个可能的解决方案。除了使用 jQuery 的 hasClass 之外,您还可以获取 class 属性作为字符串并使用 indexOf 搜索它。这可能会在某些用例中失败,因此我不建议这样做,除非是超级简单的项目。

    工作示例:

    var s = $(this).attr('class');
    if( s.indexOf('node')!==-1 ){
        // do something
    }
    

    记住:indexOf 在找不到任何东西时返回-1,而不是0。当子字符串从索引0 开始时返回0

    【讨论】:

      【解决方案3】:

      正如 Bergi 在 cmets 中指出的那样,由于 className 返回一个 SVGAnimatedString 对象而不是普通的 DOMString 对象,jQuery 在 SVG 元素上静默失败。

      请参阅this JSFiddle 进行比较。

      我很想就此提交一个拉取请求,但做了一个快速的项目搜索,显然 jQuery 项目对 SVG 问题的立场是不会修复的:https://github.com/jquery/jquery/pull/1511

      如果您使用的是D3,则可以使用d3.select(this).classed('node')。请注意,D3 正确返回 HTML 元素和 SVG 元素。

      【讨论】:

      • 如果 jQuery 的文档说明缺乏支持(或意外结果),那就太好了。 hasClass() API doc 表示 “从 jQuery 1.12/2.2 开始,此方法支持 XML 文档,包括 SVG”
      【解决方案4】:

      HTML 元素的 class 属性在 SVG 中的含义不同。

      $("<b></b>").addClass($(this).attr("class")).hasClass("node")
      

      或者

      /(^|\s)node(\s|$)/.test($(this).attr("class"))
      

      用于 SVG 元素。

      EDIT .hasClass 似乎工作得很好(至少在 IE9 和 FF 中)http://jsfiddle.net/X6BPX/1/

      所以问题可能是以下任意组合:语法错误、使用过时的浏览器、使用过时的 jQuery 版本。

      【讨论】:

      • class 在 SVG 中还有什么含义?
      • @Bergi - 它只是一个常规属性,而不是像 HTML 元素中的特殊样式属性,具有浏览器特定的钩子,如 className vs class。
      • @Bergi - jsfiddle.net/TRKF6 注意 elm.class、elm.className、elm.getAttribute('class')、elm.getAttribute('className') 与标准 HTML 元素的响应方式不同。旧版本的 jQuery 可能无法解释这些差异。
      • 不,只有className 属性产生不同的值。检查jsfiddle.net/TRKF6/1 进行比较。如果你得到其他属性的不同值,你可能应该更新你的浏览器。
      • 我不确定链接(编辑)JSFiddle 打算证明什么,因为它使用的是 div。正如问题所暗示的那样,这是一个失败的 SVG:jsfiddle.net/Mm3TE
      【解决方案5】:

      有效。但一定要关闭功能

      $(".node").hover(function(evt){
          console.log($(this).attr("class")); //returns "node"
          console.log($(this).hasClass('node')); //returns false
      }, function(){console.log("Done");});
      

      http://jsfiddle.net/X6BPX/

      【讨论】:

      • 谢谢 Rick,但我确实在 cmets 中澄清了缺少的括号是一个错字。我电脑上的功能已关闭。
      • @Rick:当hasClass('node') 返回 false 时,这是如何“工作”的?!
      • 完全没用的小提琴 - 它表明它适用于 HTML 元素。没有人对此提出质疑。手头的问题是它不适用于 SVG 元素。 (也就是说,jQuery .hasClass() 没有。)
      • 这是更正后的 Fiddle,它表明 .hasClass() 不适用于内联 SVG 元素。 jsfiddle.net/X6BPX/8
      猜你喜欢
      • 2015-09-02
      • 1970-01-01
      • 2018-07-20
      • 1970-01-01
      • 1970-01-01
      • 2019-04-15
      • 1970-01-01
      • 2023-03-12
      • 2012-11-22
      相关资源
      最近更新 更多