是否可以使用HTML的.querySelector()在SVG中通过xlink属性进行选择?

ste*_*and 36 javascript html5 svg dom xlink

鉴于:

<body>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
        <a xlink:href="url"></a>
    </svg>
</body>
Run Code Online (Sandbox Code Playgroud)

是否可以使用HTML DOM .querySelector()或.querySelectorAll()通过其xlink:href属性的内容选择SVG内的链接?

这有效:

document.querySelector('a')                    // <a xlink:href="url"/>
Run Code Online (Sandbox Code Playgroud)

这些不是:

document.querySelector('[href="url"]')         // null
document.querySelector('[xlink:href="url"]')   // Error: not a valid selector
document.querySelector('[xlink\:href="url"]')  // Error: not a valid selector
document.querySelector('[xlink\\:href="url"]') // null
Run Code Online (Sandbox Code Playgroud)

有没有办法编写该属性选择器,使其"看到" xlink:href?

Ame*_*aBR 43

查询选择器可以处理名称空间,但它变得棘手,因为

  1. 在CSS选择器中指定名称空间的语法与html不同;

  2. querySelector API没有任何方法可以将命名空间前缀(如xlink)分配给实际的命名空间(如"http://www.w3.org/1999/xlink").

在第一点上,CSS规范的相关部分允许您指定无命名空间(默认),特定命名空间或任何命名空间:

@namespace foo "http://www.example.com";
[foo|att=val] { color: blue }
[*|att] { color: yellow }
[|att] { color: green }
[att] { color: green }
Run Code Online (Sandbox Code Playgroud)

第一个规则将仅匹配具有值"val" att的" http://www.example.com "命名空间中的属性的元素.

第二个规则将仅匹配具有属性的元素,而att不管属性的名称空间(包括没有名称空间).

最后两个规则是等效的,并且仅匹配具有att属性不在命名空间中的属性的元素.

看到这个小提琴,注意填充样式(默认,悬停和活动):https:
//jsfiddle.net/eg43L/

Selectors API采用CSS选择器语法,但没有与@namespace定义命名空间的规则等效.因此,具有名称空间的选择器无效,但通配符名称空间标记有效:

如果选择器组包含需要解析的命名空间前缀,则实现必须引发SYNTAX_ERR异常([DOM-LEVEL-3-CORE],第1.4节).

此规范不支持解析任意名称空间前缀.但是,可以考虑支持名称空间前缀解析机制以包含在本说明书的未来版本中.

如果命名空间组件既不是空的(例如|div),表示空命名空间,也不是星号(例如*|div),表示任何命名空间,则需要解析名称空间前缀.由于不需要解析星号或空名称空间前缀,因此支持选择器中的名称空间语法的实现必须支持这些.

(加粗)

再次检查小提琴,这次注意控制台输出.该命令document.querySelector('[*|href="#url"]')返回所需的元素.

最后一个警告:MDN告诉我IE8-不支持CSS命名空间,因此这可能对他们不起作用.


更新2015-01-31:

正如@ Netsi1964在评论中指出的那样,这不适用于HTML 5文档中的自定义命名空间属性,因为HTML不支持XML命名空间.(它可以在独立的SVG或包含XHTML的其他XML文档中工作.)

当HTML5解析器遇到属性时,data:myAttribute="value"它会将其视为属性名称的单个字符串,包括:.为了让事情更加混乱,它会自动缩小字符串.

要querySelector选择这些属性,您必须包含data:属性字符串的一部分.但是,由于:CSS选择器具有特殊含义,因此需要使用\字符对其进行转义.既然你需要\获得通过选择作为一部分传递,你需要逃避它在你的JavaScript.

因此成功的电话看起来像:

document.querySelector('[data\\:myattribute="value"]');
Run Code Online (Sandbox Code Playgroud)

为了使事情更合理,我建议使用所有小写字母作为属性名称,因为HTML 5解析器无论如何都会转换它们.Blink/Webkit浏览器将自动小写您传递的选择器querySelector,但这实际上是一个非常有问题的错误(意味着您永远不能选择具有混合大小写标记名称的SVG元素).

但同样的解决方案是否有效xlink:href?没有!HTML 5解析器xlink:href在SVG标记中识别,并正确地将其解析为命名空间属性.

这是更新的小提琴,附加测试.再次,查看控制台输出以查看结果.在Chrome 40,Firefox 35和IE 11中测试过; 行为的唯一区别是Chrome匹配混合大小写选择器.

  • 是的。通配符的意思是“任何命名空间或没有命名空间”。因此,如果您想区分 SVG 中的“a”元素和其他锚点或具有“href”属性的元素,则需要对选择器的其余部分更加明确。(是的,我完全没有考虑 IE8 与 SVG 无关的事实......) (2认同)
  • 我已经在SVG元素中添加了一个命名空间`data`,并在该命名空间中使用了一个自定义属性`onewaybinding`,但我无法使用以下命令检测具有该属性的元素:`document.querySelectorAll("[*| onewaybinding]")`.所以我回到了旧的数据属性,它给出了验证错误,但是我可以使用`querySelector`找到元素:-)`data-onewaybinding`可以使用`document.querySelector("[data-onewaybinding]")找到` (2认同)
  • @ Netsi1964这很烦人(但很高兴知道!).我玩了一下 - 看看答案的更新.我想我也会考虑你的解决方案,该死的验证器.W3C SVG工作组一直在讨论在SVG 2中正式允许SVG元素的HTML 5风格"数据"属性,因为很多人已经使用它们.但是,没有办法在XML验证方案中真正描述它们. (2认同)

log*_*yth 6

不幸的是.

querySelector不处理XML命名空间,因此没有简单的方法可以这样做.但是,您可以使用XPath查询.

var result = document.evaluate(
    // Search for all nodes with an href attribute in the xlink namespace.
    '//*[@xlink:href="url"]',
    document,
    function(prefix){
        return {
            xlink: "http://www.w3.org/1999/xlink"
        }[prefix] || null;
    },
    XPathResult.ORDERED_NODE_ITERATOR_TYPE
);

var element = result.iterateNext();
Run Code Online (Sandbox Code Playgroud)

如果您需要完整的跨浏览器支持,例如对于没有a的IE document.evaluate,您可以使用wicked-good-xpath对其进行填充.

当然,根据您的使用情况,可能更容易做到这一点(我认为这将适用于IE):

var element = Array.prototype.filter.call(document.querySelectorAll('a'),
    function(el){
    return el.getAttributeNS('http://www.w3.org/1999/xlink', 'href') === 'url';
})[0] || null;
Run Code Online (Sandbox Code Playgroud)


cui*_*ing 6

[*|href]将同时匹配html href和svg xlink:href,然后用于:not([href])排除html href。

document.querySelectorAll('[*|href]:not([href])')
Run Code Online (Sandbox Code Playgroud)

经过镀铬测试

  • 终于有人给出了真正有效的答案!(也很聪明!) (2认同)
  • 扩展答案:如果您想匹配精确值: document.querySelector('[*|href="#icon-edit"]:not([href])') #icon-edit 是 xlink:href 属性的值 (2认同)