44

我正在尝试检测是否注册了具有特定名称的自定义元素。有没有办法进行这样的检查?

或者有没有办法获取已注册的自定义元素列表?

我有document.registerElement,但还有什么?它是单向API吗?

4

8 回答 8

54

有一种方法可以检查元素是否已注册。已注册的元素有自己的构造函数,而未注册的元素将使用 plainHTMLElement()作为构造函数(或者HTMLUnknownElement()名称是否无效,但这超出了问题的范围):

document.registerElement('x-my-element');
document.createElement('x-my-element').constructor
//⇒ function x-my-element() { [native code] }
document.createElement('x-my-element-not-registered').constructor
//⇒ function HTMLElement() { [native code] }

也就是说,检查器可能看起来像:

var isRegistered = function(name) {
  return document.createElement(name).constructor !== HTMLElement;
}

或者,使用语法糖:

String.prototype.isRegistered = function() { 
  return document.createElement(this).constructor !== HTMLElement; 
}
'x-my-element'.isRegistered()
//⇒ true
'xx-my-element'.isRegistered()
//⇒ false

最谨慎的版本:

String.prototype.wasRegistered = function() { 
  switch(document.createElement(this).constructor) {
    case HTMLElement: return false; 
    case HTMLUnknownElement: return undefined; 
  }
  return true;
}
'x-my-element'.wasRegistered()
//⇒ true
'xx-my-element'.wasRegistered()
//⇒ false
'xx'.wasRegistered()
//⇒ undefined

无法访问已注册元素的列表,AFAIK。

顺便说一句,我仍然认为try-catch注册(由@stephan-muller 提出)更适合您的需求。

于 2015-01-29T08:46:41.607 回答
38

由于自定义元素现在是最新标准的一部分,我想我会在 2017+ 年分享如何做到这一点:

注意:该document.registerElement函数已被弃用,取而代之的是 customElements.define()。

customElements被定义为一个全局的window定义了三种方法

  1. define
  2. get
  3. whenDefined

get是这里重要的一个。get接受string元素名称并返回命名自定义元素的构造函数,或者undefined如果名称没有自定义元素定义。

因此,在 2017+ 年检查元素是否已注册:

const myElementExists = !!customElements.get('my-element');

但是,我不确定是否有办法获取已定义元素的列表。


注意:这在 IE 中不起作用。请参阅此处了解浏览器兼容性

于 2017-02-24T06:48:59.470 回答
30

编辑(2021 年):这不再像/deep/几年前那样有效。


结合上述几种方法,您可以迭代所有正在使用的内容并生成一个唯一的自定义(和注册)元素列表:

function isRegistered(name) {
  return document.createElement(name).constructor.__proto__ !== window.HTMLElement;
}

var allElems = document.querySelectorAll('html /deep/ *');
var nodeNames = [].map.call(allElems, el => el.nodeName.toLowerCase())
                    .filter((value, index, self) => self.indexOf(value) === index)

console.log('all elements', nodeNames);
console.log('registered, custom elements', nodeNames.filter(isRegistered))

在此处输入图像描述

于 2015-12-16T20:54:05.160 回答
10

目前似乎没有办法查看所有注册的元素,但是有一种方法可以检查一个元素是否已经注册:将寄存器包装在一个try...catch块中:

try {
    document.registerElement('x-my-element');
} catch(e) {
    console.log('already exists', e);
}

在控制台中运行两次,您将看到记录的错误。

如果您只是想检查它是否已注册,这确实有一个缺点:如果没有,它将在运行它之后。似乎也没有办法取消注册元素。

于 2014-12-07T02:02:36.103 回答
7

虽然我不确定它是否适用于其他 Web 组件框架,但在 Chrome 中使用 Polymer 时,我有一个CustomElements对象window。该CustomElements对象具有所有已注册的自定义元素的键/值集合,称为registry.

function isRegistered(name) {
    if (window.CustomElements && window.CustomElements.registry)
        return name in window.CustomElements.registry;
    return undefined;
}
于 2015-02-01T05:30:31.837 回答
3

正如已经在 Polymer 的 Slack 频道上写的那样,这是一个可以完成这项工作的肮脏的:

function isElementRegistered(elementId) {
  return Polymer.telemetry.registrations.find(function(item) { return item.is === elementId })
}

不确定多少Polumer.telemetry.registrations是可靠的(在文档上没有看到)并且Array.prototype.find不是跨浏览器!

于 2016-02-09T12:27:02.073 回答
1

在自定义元素类(构造函数)自注册元素的场景中,检查该类的存在就足够了

于 2017-11-09T13:28:09.990 回答
1

这是获取所有customElements使用 ES6注册的列表的一种方法

// Get all elements
const elements = document.querySelectorAll('*')

// Create an array from elements
const elementArray = Array.from(elements)

// Map to node names
const nodeNames = elementArray.map(element => element.nodeName.toLowerCase())

// Filter by which ones are registered
const allCustomElementNames = nodeNames.filter(customElements.get.bind(customElements))
于 2021-04-30T18:24:38.803 回答