是否可以使用 HTML 的 .querySelector() 通过 SVG 中的 xlink 属性进行选择?
-
21-12-2019 - |
题
鉴于:
<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()
通过其内容选择 SVG 内的链接 xlink:href
属性?
这有效:
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
?
解决方案
查询选择器 能 处理命名空间,但这变得很棘手,因为
CSS 选择器中指定命名空间的语法与 html 不同;
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 }
第一条规则将仅匹配具有该属性的元素
att
在里面 ”http://www.example.com" 具有值“val”的命名空间。第二条规则将仅匹配具有该属性的元素
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年1月31日更新:
正如 @Netsi1964 在评论中指出的那样,这不适用于 HTML 5 文档中的自定义命名空间属性,因为 HTML 不支持 XML 命名空间。(它可以在独立的 SVG 或其他 XML 文档(包括 XHTML)中工作。)
当 HTML5 解析器遇到类似这样的属性时 data:myAttribute="value"
它将其视为属性名称的单个字符串,包括 :
. 。为了让事情变得更加混乱,它会自动将字符串小写。
要得到 querySelector
要选择这些属性,您必须包括 data:
作为属性字符串的一部分。然而,自从 :
在 CSS 选择器中有特殊含义,你需要用 \
特点。既然你需要 \
要作为选择器的一部分传递,您需要转义 它 在你的 JavaScript 中。
因此,成功的调用如下所示:
document.querySelector('[data\\:myattribute="value"]');
为了使事情更符合逻辑,我建议您的属性名称全部使用小写,因为 HTML 5 解析器无论如何都会转换它们。Blink/Webkit 浏览器会自动将您传递的选择器小写 querySelector
, ,但这实际上是一个非常有问题的错误(这意味着您永远无法选择具有混合大小写标签名称的 SVG 元素)。
但同样的解决方案适用于 xlink:href
?不!HTML 5 解析器识别 xlink:href
SVG 标记中,并将其正确解析为命名空间属性。
这是带有附加测试的更新后的小提琴. 。再次查看控制台输出以查看结果。在 Chrome 40、Firefox 35 和 IE 11 中测试;行为上的唯一区别是 Chrome 匹配大小写混合的选择器。
其他提示
不幸的是没有。
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();
如果您需要完整的跨浏览器支持,例如 IE,它没有 document.evaluate
, ,你可以将其填充为 邪恶-善良-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;
[*|href]
将匹配两个 html href
和 svg xlink:href
, ,然后使用 :not([href])
排除 html href
.
document.querySelectorAll('[*|href]:not([href])')
在镀铬中测试