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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23034283/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 00:12:47  来源:igfitidea点击:

Is it possible to use HTML's .querySelector() to select by xlink attribute in an SVG?

javascripthtmldomsvgxlink

提问by stephband

Given:

鉴于:

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

Is it possible to use the HTML DOM's .querySelector()or .querySelectorAll()to select the link inside the SVG by the contents of its xlink:hrefattribute?

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

This works:

这有效:

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

These don't:

这些没有:

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

Is there a way of writing that attribute selector to make it 'see' the xlink:href?

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

回答by AmeliaBR

Query selector canhandle namespaces, but it gets tricky because

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

  1. The syntax for specifying namespaces in CSS selectors is different from html;

  2. The querySelector API doesn't have any method for assigning a namespace prefix (like xlink) to an actual namespace (like "http://www.w3.org/1999/xlink").

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

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

On the first point, the relevant part of the CSS specsallows you to specify nonamespace (the default), a specific namespace, or anynamespace:

首先,CSS 规范的相关部分允许您指定命名空间(默认)、特定命名空间或任何命名空间:

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

The first rule will match only elements with the attribute attin the "http://www.example.com" namespace with the value "val".

The second rule will match only elements with the attribute attregardless of the namespace of the attribute (including no namespace).

The last two rules are equivalent and will match only elements with the attribute attwhere the attribute is notin a namespace.

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

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

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

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

See this fiddle, paying attention to the fill styles (default, hover, and active):
https://jsfiddle.net/eg43L/

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

The Selectors API adopts the CSS selector syntax, but has no equivalent to the @namespacerule for defining a namespace. As a result, selectors with namespaces are not valid butthe wildcard namespace token is valid:

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

If the group of selectors include namespace prefixes that need to be resolved, the implementation must raise a SYNTAX_ERR exception ([DOM-LEVEL-3-CORE], section 1.4).

This specification does not provide support for resolving arbitrary namespace prefixes. However, support for a namespace prefix resolution mechanism may be considered for inclusion in a future version of this specification.

A namespace prefix needs to be resolved if the namespace component is neither empty (e.g. |div), representing the null namespace, or an asterisk (e.g. *|div), representing any namespace. Since the asterisk or empty namespace prefix do not need to be resolved, implementations that support the namespace syntax in Selectors must support these.

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

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

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

(bold added)

(加粗)

Check out the fiddleagain, this time paying attention to the console output. The command document.querySelector('[*|href="#url"]')returns the element you want.

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

One final warning: MDNtells me that IE8- do not support CSS namespaces, so this might not work for them.

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



Update 2015-01-31:

2015-01-31 更新:

As @Netsi1964 pointed out in the comments, this doesn't work for custom namespaced attributes in HTML 5 documents, since HTML doesn't support XML namespaces. (It would work in a stand-alone SVG or other XML document including XHTML.)

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

When the HTML5 parser encounters an attribute like data:myAttribute="value"it treats that as a single string for the attribute name, including the :. To make things more confusing, it auto-lowercases the string.

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

To get querySelectorto select these attributes, you have to include the data:as part of the attribute string. However, since the :has special meaning in CSS selectors, you need to escape it with a \character. And since you need the \to get passed through as part of the selector, you need to escape itin your JavaScript.

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

The successful call therefore looks like:

因此,成功的调用看起来像:

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

To make things a little more logical, I would recommend using all lower-case for your attribute names, since the HTML 5 parser will convert them anyway. Blink/Webkit browser will auto-lowercase selectors you pass querySelector, but that's actually a very problematic bug (in means you can never select SVG elements with mixed-case tag names).

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

But does the same solution work for xlink:href? No! The HTML 5 parser recognizes xlink:hrefin SVG markup, and correctly parses it as a namespaced attribute.

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

Here's the updated fiddle with additional tests. Again, look at the console output to see the results. Tested in Chrome 40, Firefox 35, and IE 11; the only difference in behavior is that Chrome matches the mixed-case selector.

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

回答by loganfsmyth

Unfortunately not.

不幸的是没有。

querySelectordoesn't handle XML namespaces, so there is no easy way to do this that way. You can however use an XPathquery.

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

If you need full cross-browser support, such as for IE, which does not have a document.evaluate, you can polyfill it with wicked-good-xpath.

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

Of course, depending on your usage, it may be easier to do this (which I think will work on IE):

当然,根据您的使用情况,这样做可能更容易(我认为这适用于 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;

回答by cuixiping

[*|href]will match both html hrefand svg xlink:href, then use :not([href])to exclude html href.

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

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

tested in chrome

在铬中测试