SVG 元素的 jQuery .hasClass() 方法失败

Posted

技术标签:

【中文标题】SVG 元素的 jQuery .hasClass() 方法失败【英文标题】:jQuery .hasClass() method fails for SVG elements 【发布时间】:2013-07-24 08:11:22 【问题描述】:

我有一组带有 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 修复了这个问题 - 你可以在这里看到我的帖子:***.com/a/34698009/3885376 包含一些细节 + 一个小例子,现在是 hasClass()addClass()removeClass() 工作。 【参考方案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

以上是关于SVG 元素的 jQuery .hasClass() 方法失败的主要内容,如果未能解决你的问题,请参考以下文章

jQuery + One Page Scroll 插件:检查元素 hasClass 是不是不起作用

jQuery.hasClass() 函数详解

jQuery.hasClass() 函数详解

jQuery hasClass() - 检查多个类

jquery e.target.hasClass 不工作

JQuery属性操作 addclass removeclass hasclass toggleClass()