我正在尝试检测是否注册了具有特定名称的自定义元素。有没有办法进行这样的检查?
或者有没有办法获取已注册的自定义元素列表?
我有document.registerElement
,但还有什么?它是单向API吗?
我正在尝试检测是否注册了具有特定名称的自定义元素。有没有办法进行这样的检查?
或者有没有办法获取已注册的自定义元素列表?
我有document.registerElement
,但还有什么?它是单向API吗?
有一种方法可以检查元素是否已注册。已注册的元素有自己的构造函数,而未注册的元素将使用 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 提出)更适合您的需求。
由于自定义元素现在是最新标准的一部分,我想我会在 2017+ 年分享如何做到这一点:
注意:该
document.registerElement
函数已被弃用,取而代之的是 customElements.define()。
customElements
被定义为一个全局的window
。定义了三种方法:
define
get
whenDefined
get
是这里重要的一个。get
接受string
元素名称并返回命名自定义元素的构造函数,或者undefined
如果名称没有自定义元素定义。
因此,在 2017+ 年检查元素是否已注册:
const myElementExists = !!customElements.get('my-element');
但是,我不确定是否有办法获取已定义元素的列表。
注意:这在 IE 中不起作用。请参阅此处了解浏览器兼容性
编辑(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))
目前似乎没有办法查看所有注册的元素,但是有一种方法可以检查一个元素是否已经注册:将寄存器包装在一个try...catch
块中:
try {
document.registerElement('x-my-element');
} catch(e) {
console.log('already exists', e);
}
在控制台中运行两次,您将看到记录的错误。
如果您只是想检查它是否已注册,这确实有一个缺点:如果没有,它将在运行它之后。似乎也没有办法取消注册元素。
虽然我不确定它是否适用于其他 Web 组件框架,但在 Chrome 中使用 Polymer 时,我有一个CustomElements
对象window
。该CustomElements
对象具有所有已注册的自定义元素的键/值集合,称为registry
.
function isRegistered(name) {
if (window.CustomElements && window.CustomElements.registry)
return name in window.CustomElements.registry;
return undefined;
}
正如已经在 Polymer 的 Slack 频道上写的那样,这是一个可以完成这项工作的肮脏的:
function isElementRegistered(elementId) {
return Polymer.telemetry.registrations.find(function(item) { return item.is === elementId })
}
不确定多少Polumer.telemetry.registrations
是可靠的(在文档上没有看到)并且Array.prototype.find
不是跨浏览器!
在自定义元素类(构造函数)自注册元素的场景中,检查该类的存在就足够了
这是获取所有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))