这不起作用:
<!-- wtf.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title></title>
<script type="module" src="./wtf.js"></script>
</head>
<body>
<script>
const myElement = document.createElement('my-element')
document.body.appendChild(myElement)
myElement.callMe()
</script>
</body>
</html>
// wtf.js
customElements.define('my-element', class extends HTMLElement {
constructor() {
super()
}
callMe() {
window.alert('I am called!')
}
})
Firefox 在线向我抛出了一个令人讨厌的异常myElement.callMe()
。显然,“ myElement.callMe is not a function
”。
我很困惑为什么会这样?据我了解,一旦我输入const myElement = document.createElement('my-element')
,我就会收到一个类型不是泛型HTMLElement
的对象,而是我编写的扩展类的对象HTMLElement
!而这个类暴露了callMe
.
我已经确认我对模块的使用似乎是这里的罪魁祸首。此代码按预期工作:
<!-- wtf.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title></title>
</head>
<body>
<script>
customElements.define('my-element', class extends HTMLElement {
constructor() {
super()
}
callMe() {
window.alert('I am called!')
}
})
const myElement = document.createElement('my-element')
document.body.appendChild(myElement)
myElement.callMe()
</script>
</body>
</html>
是的,我知道一个模块中定义的东西的范围是这个模块。但在这里,它甚至(对我而言)似乎都不是范围界定问题。例如,如果我在一个模块中做这样的事情:
function callMe() {/*blah blah */}
window.callMe = callMe
那么我无论如何都可以callMe
在模块外部使用,因为模块通过其他方式暴露了这个功能export
(这次是通过将它分配给全局window
对象)。
据我了解,在我的用例中也应该发生同样的情况。即使我callMe
在一个作用域为模块的类中定义,这个类方法也应该可以在模块外部访问,因为它是这个类的对象的属性,通过调用document.createElement('my-element')
. 然而显然,这不会发生。
这对我来说真的很奇怪。似乎模块通过与类型不相关的函数返回 (!!) 纠缠来强制其范围界定- 所以在这种情况下,就好像模块神奇地强制document.createElement
转换它在继承层次结构中返回的对象(到HTMLElement
)?!?! 这对我来说是令人兴奋的。
有人可以解决我的困惑吗?
(如果我在模块内定义了一个自定义元素,我如何在这个模块之外公开它的 API?)