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

Posted

技术标签:

【中文标题】是否可以使用 HTML 的 .querySelector() 通过 SVG 中的 xlink 属性进行选择?【英文标题】:Is it possible to use HTML's .querySelector() to select by xlink attribute in an SVG? 【发布时间】:2014-05-26 21:20:51 【问题描述】:

给定:

<body>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
        <a xlink:href="url"></a>
    </svg>
</body>

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

这行得通:

document.querySelector('a')                    // <a xlink:href="url"/>

这些不:

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

有没有办法编写该属性选择器以使其“看到”xlink:href

【问题讨论】:

【参考方案1】:

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

    CSS选择器中指定命名空间的语法与html不同;

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

首先,the relevant part of the CSS specs 允许您指定 no 命名空间(默认)、特定命名空间或 any 命名空间:

@namespace foo "http://www.example.com";
[foo|att=val]  color: blue 
[*|att]  color: yellow 
[|att]  color: green 
[att]  color: green 

第一条规则将仅匹配“http://www.example.com”命名空间中属性为“att”且值为“val”的元素。

第二条规则将只匹配具有att 属性的元素,而不管该属性的命名空间(包括没有命名空间)。

最后两条规则是等价的,只会匹配名称空间中具有属性att 且属性的元素。

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

Selectors API 采用 CSS 选择器语法,但没有等效于用于定义命名空间的 @namespace 规则。结果,selectors with namespaces are not valid but the wildcard namespace token is valid:

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

本规范不支持解析任意命名空间前缀。但是,可能会考虑在本规范的未来版本中包含对命名空间前缀解析机制的支持。

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

(加粗)

再次查看the fiddle,这次注意控制台输出。命令document.querySelector('[*|href="#url"]') 返回你想要的元素。

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


2015-01-31 更新:

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

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

要让querySelector 选择这些属性,您必须将data: 作为属性字符串的一部分。但是,由于 : 在 CSS 选择器中具有特殊含义,因此您需要使用 \ 字符对其进行转义。而且由于您需要 \ 作为选择器的一部分通过,您需要在 javascript 中转义 it

因此,成功的调用如下所示:

document.querySelector('[data\\:myattribute="value"]');

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

但同样的解决方案是否适用于xlink:href?不! HTML 5 解析器识别 SVG 标记中的 xlink:href,并将其正确解析为命名空间属性。

Here's the updated fiddle with additional tests。同样,查看控制台输出以查看结果。在 Chrome 40、Firefox 35 和 IE 11 中测试;唯一不同的行为是 Chrome 匹配大小写混合选择器。

【讨论】:

是的。通配符的意思是“任何或没有命名空间”。因此,如果您想区分 SVG 中的 a 元素和其他具有 href 属性的锚点或元素,则需要更明确地使用选择器的其余部分。 (是的,我完全没想到 IE8 与 SVG 无关……) 我已将命名空间 data 添加到 SVG 元素,并在该命名空间 onewaybinding 中使用自定义属性,但我无法使用 document.querySelectorAll("[*|onewaybinding]") 检测具有该属性的元素。所以我回到了良好的旧数据属性,它给出了一个验证错误,但我可以使用 querySelector 找到元素 :-) 可以使用 document.querySelector("[data-onewaybinding]") 找到 data-onewaybinding @Netsi1964 这很烦人(但很高兴知道!)。我玩了一会儿-查看答案的更新。我想我也会采用您的解决方案,并且该死的验证器。 W3C SVG 工作组一直在讨论在 SVG 2 中允许 HTML 5 样式的data- 属性在 SVG 元素上,因为已经有很多人在使用它们。但是,没有办法在 XML 验证方案中真正描述它们。 汉! document.querySelector('[*|href="#url"]') 在 IE 中不起作用...(9 到 11 测试) 刚刚安装了一个Edge VM,也可以在那里确认。而且它甚至不会抛出错误,它只是没有找到任何东西......唯一可以做的检查似乎是首先附加一个具有这种命名空间属性的元素,然后尝试获取它......【参考方案2】:

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

document.querySelectorAll('[*|href]:not([href])')

在 chrome 中测试

【讨论】:

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

很遗憾没有。

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

如果您需要完整的跨浏览器支持,例如没有document.evaluate 的IE,您可以使用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;

【讨论】:

似乎没有 Internet Explorer 对 XPath 查询的支持。 我正在投票,因为我学到了一些有用的东西,但我犹豫是否将其标记为正确,因为我不希望其他人开始使用无法使用 x-browser 的东西。我想正确的答案是“不”。 是的,我已经实现了过滤后的数组版本,虽然它看起来更像 [编辑:啊,gack,无法将代码放在此处可读]。 好的,谢谢,所有有用的东西。我将坚持使用过滤后的数组版本,因为我不拥有我目前正在为其编写的网站,并且我需要注意外部库。

以上是关于是否可以使用 HTML 的 .querySelector() 通过 SVG 中的 xlink 属性进行选择?的主要内容,如果未能解决你的问题,请参考以下文章

Testcafe - 处理视频

IOS系统兼容input keyup事件

移动端实现元素局部滚动(滚动某元素时不滚动整个网页)

来自 chrome 控制台的聚合物属性

上拉刷新后台完整版

通过 id 定位元素