为什么通过JS向HTML文档添加`svg`标签时需要使用`document.createElementNS`?

问题描述 投票:0回答:3

这行不通:

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 元素需要

xmlns
属性。对于内部 svg 元素或 HTML 文档内部是不必要的。

好吧,我将

svg
嵌套在 HTML 中,所以
xmlns
属性应该不是必需的,不是吗?

Q2:这种情况可以避免吗?

每次都用手打字

document.createElementNS('http://www.w3.org/2000/svg', 'rect')

很烦人。 

还有更短的路吗?

javascript svg xml-namespaces
3个回答
7
投票
如果你调用 document.createElement("a") 它应该创建哪个

<a>

 ? HTML 的还是 SVG 的?问题就在这里。同上脚本等。在appendChild步骤之前你没有给浏览器任何猜测的机会,到那时就太晚了。

您可以通过

innerHTML 在没有命名空间的情况下完成此操作,因为它需要一个包含所有标记的字符串,以便浏览器可以一步解析和添加,从而推断出正确的命名空间。

或者只是创建一个包装函数

function createSVGElement(tag) { return document.createElementNS('http://www.w3.org/2000/svg', tag) }
    

0
投票
首先,举个不“工作”的例子:它按预期工作。但很难说怎么做,因为周围的 HTML 文档代码没有显示。我猜测由于这个问题,解析器(和浏览器)不会将创建的元素解释为 svg 元素。

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 解析器将为该元素分配您声明的名称空间。或者换句话说,如果您的文档树定义了该元素的名称空间属性,则文档编写器也将通过使用默认名称空间或名称空间前缀在序列化文档中正确声明名称空间。


0
投票
我猜

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');
    
© www.soinside.com 2019 - 2024. All rights reserved.