首页 > 解决方案 > setAttributeNS xmlns 的 for a general-purpose library

问题描述

DOMException当使用元素设置属性时setAttributeNS,Web 浏览器似乎会抛出一个错误。IE<svg>xmlns

>>> s = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
<svg>​&lt;/svg>​

>>> s.setAttributeNS(null, 'xmlns', '123')
Uncaught DOMException: Failed to execute 'setAttributeNS' 
  on 'Element': '' is an invalid namespace for attributes.

>>> s.setAttributeNS('http://www.w3.org/2000/svg', 'xmlns', 
      'http://www.w3.org/2000/svg')
Uncaught DOMException: Failed to execute 'setAttributeNS' 
  on 'Element': '' is an invalid namespace for attributes.

>>> s.setAttributeNS(null, 'xmlns', 'http://www.w3.org/2000/svg')
Uncaught DOMException: Failed to execute 'setAttributeNS' 
  on 'Element': '' is an invalid namespace for attributes.

Mozilla 文档建议始终使用,setAttributeNS但它没有提到这种可能性。因此,该建议似乎有一些警告。

DOM Level 2 规范给出了一些setAttributeNS见解:

NAMESPACE_ERR:如果qualifiedName 格式错误,如果qualifiedName 有前缀并且namespaceURI 为null,如果qualifiedName 有前缀“xml”并且namespaceURI 不同于“ http://www.w3.org/XML ”,则引发/1998/namespace ”,或者如果qualifiedName 是“xmlns”并且namespaceURI 不同于“ http://www.w3.org/2000/xmlns/ ”。

所以这个特殊的例外似乎是更广泛的可能失败的案例的一部分。目前还不清楚这些案例是什么。

我正在编写 tko / Knockout 4.0,一个通用的 Web 框架,因此它应该支持svg核心 HTML 命名空间之外的其他标签。

最常遇到的问题来自xmlnssvg标签,所以这是一个问题。我已经通过专门检查是否xmlns这种情况下设置和使用来解决setAttribute这个问题。

该解决方法似乎非常具体,我担心一般情况。setAttributeNS是否有关于如何使用和处理设置属性的先例setAttribute

其他 web 框架并没有很好地解决这个问题——它通常与其他逻辑混合在一起;我见过的最直接的提交是angular,但它并没有直接解决这个问题。

相关:setAttribute 和 setAttributeNS(null,

标签: javascriptxmldomsvg

解决方案


它不会涵盖所有情况,但这应该有很长的路要走:

const NAMESPACES = {
  svg: 'http://www.w3.org/2000/svg',
  html: 'http://www.w3.org/1999/xhtml',
  xml: 'http://www.w3.org/XML/1998/namespace',
  xlink: 'http://www.w3.org/1999/xlink',
  xmlns: 'http://www.w3.org/2000/xmlns/' // sic for the final slash...
}

class JsxObserver extends LifeCycle {
  ...

  setNodeAttribute (node, name, valueOrObservable) {
    const value = unwrap(valueOrObservable)
    NativeProvider.addValueToNode(node, name, valueOrObservable)
    if (value === undefined) {
      node.removeAttributeNS(null, name)
    } else if (isThenable(valueOrObservable)) {
      Promise.resolve(valueOrObservable)
        .then(v => this.setNodeAttribute(node, name, v))
    } else {
      const [prefix, ...unqualifiedName] = name.split(':')
      let ns = null
      if (prefix === 'xmlns' || unqualifiedName.length && NAMESPACES[prefix]) {
        ns = NAMESPACES[prefix]
      }
      node.setAttributeNS(ns, name, String(value))
    }
  }
}

如果遇到的属性是xmlns="http://www.w3.org/2000/svg",它将添加

.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.w3.org/2000/svg')

如果遇到的属性是xml:space="preserve"(SVG 编辑器臭名昭著地使用的东西),它将被添加

.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve')

推荐阅读