这行不通:
const svg = document.createElement('svg')
svg.setAttribute('height', '100')
svg.setAttribute('width', '100')
document.body.appendChild(svg)
const rect = document.createElement('rect')
rect.setAttribute('height', '100%')
rect.setAttribute('width', '100%')
rect.setAttribute('fill', 'red')
svg.appendChild(rect)
这会起作用:
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
svg.setAttribute('height', '100')
svg.setAttribute('width', '100')
document.body.appendChild(svg)
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('height', '100%')
rect.setAttribute('width', '100%')
rect.setAttribute('fill', 'red')
svg.appendChild(rect)
显然,每次通过 JS 创建
svg
标签或其任何后代时,我都需要明确指定名称空间。
Q1:为什么有必要这样做?引用 svg
标签上的MDN 文档:
注意:仅 SVG 文档最外层的 svg 元素需要
属性。对于内部 svg 元素或 HTML 文档内部是不必要的。xmlns
好吧,我将
svg
嵌套在 HTML 中,所以 xmlns
属性应该不是必需的,不是吗?
Q2:这种情况可以避免吗?
每次都用手打字document.createElementNS('http://www.w3.org/2000/svg', 'rect')
很烦人。还有更短的路吗?
<a>
? HTML 的还是 SVG 的?问题就在这里。同上脚本等。在appendChild步骤之前你没有给浏览器任何猜测的机会,到那时就太晚了。您可以通过
innerHTML 在没有命名空间的情况下完成此操作,因为它需要一个包含所有标记的字符串,以便浏览器可以一步解析和添加,从而推断出正确的命名空间。
或者只是创建一个包装函数
function createSVGElement(tag) {
return document.createElementNS('http://www.w3.org/2000/svg', tag)
}
Q1 - 为什么需要指定命名空间?
xmlns
属性为该属性所在的子文档声明默认命名空间。每个没有命名空间前缀的元素都属于默认命名空间。如果您将 svg 嵌套在 HTML 文档中,我猜默认命名空间将是 HTML 命名空间(任何 HTML 版本都可能),因为在 HTML 文档中没有其他命名空间有意义。然后,命名空间感知解析器将读取
h:rect
等元素,其中
h
是该 HTML 命名空间的前缀。Q2 - 可以避免吗?好吧,如果你真的想要,还有其他方法可以解决它,但不避免它要容易得多。换句话说,没有比这更短的方法了。
我们也看看你对 svg“标签”的引用:
注意:仅 SVG 文档最外层的 svg 元素需要 xmlns 属性。对于内部 svg 元素或 HTML 文档内部是不必要的。本注释是关于序列化文档的。它没有说明文档树或如何构建它。
createElement
和
createElementNS
将元素节点添加到文档树中。文档树可以通过不同的方式序列化为 XML 文档,例如使用
xmlns
属性的默认命名空间或使用
xmlns:svg
属性单独声明的每个命名空间等。重要的是您需要 svg 元素的命名空间限定名称。否则它们不会被解释为 svg 元素。如果您在 XML 文档中声明名称空间,XML 解析器将为该元素分配您声明的名称空间。或者换句话说,如果您的文档树定义了该元素的名称空间属性,则文档编写器也将通过使用默认名称空间或名称空间前缀在序列化文档中正确声明名称空间。
document.createElement
作为HTML
document
的一种方法,在创建元素时使用自己的名称空间而不告诉名称空间。因此,当它创建
circle
元素时,它根本不是
svg:circle
元素。目前,
svg.createElement
似乎尚未实施。它将允许写入
document.getElementsByTagname('svg').createElement('circle')
,这将产生一个真正的
svg:circle
,因为
createElement
方法现在属于被调用者
svg
元素。如果文档是严格的 XML 文档,则语法
<svg:circle />
是可能的,如果
xmlns:svg='http://www.w3.org/2000/svg'
在根节点中声明如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html
xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
xmlns:svg="http://www.w3.org/2000/svg">
<h1>My circle</h1>
<svg:circle cx="20" cy="20" r="10" />
</html>
这样的文档,我没有测试过,也许可以这么写:
document.createElement('svg:circle');