自定义元素类型在脚本类型=模块中加载时报告 HTMLElement?

custom element type reports HTMLElement when loaded in script type=module?

我正在使用自定义元素,我注意到在一个案例中我无法访问实例的属性,如 var prop = myCustomElement.myPropery // undefined 中 属性 是在 [=44= 中定义的] 例如get myProperty() { blah }.

当自定义元素在脚本中定义时,我将问题归结为 myCustomElement.constructor 中报告的内容(因此 prototype/instance 类型) type="module"对比没有模块类型。

这是一个非常简单的例子:

var test = document.getElementById ( "test" );

console.log ( test.mood, test.constructor );
<script type="module">
const template = document.createElement ( "template" );

template.innerHTML = "<span>Hello!</span>";

window.customElements.define ( "test-case",

class TestCase extends window.HTMLElement {
    constructor () {
        super ();
        
        var frag = template.content.cloneNode ( true ),
            shadow = this.attachShadow( { mode: "open" } );
        
        shadow.appendChild ( frag );
    }
    
    get mood () {
        return "Happy!";
    }
} );
</script>
<test-case id="test"></test-case>

...并且没有模块类型

var test = document.getElementById ( "test" );

console.log ( test.mood, test.constructor );
<script>
const template = document.createElement ( "template" );

template.innerHTML = "<span>Hello!</span>";

window.customElements.define ( "test-case",

class TestCase extends window.HTMLElement {
    constructor () {
        super ();
        
        var frag = template.content.cloneNode ( true ),
            shadow = this.attachShadow( { mode: "open" } );
        
        shadow.appendChild ( frag );
    }
    
    get mood () {
        return "Happy!";
    }
} );
</script>
<test-case id="test"></test-case>

这似乎很不对,这是故意的吗?

而且,假设需要使用一个模块,例如定义要在更大的组件或库中使用的自定义元素,是否有直接的方法来防止模块隐藏自定义元素的类型?

注意:我正在从最新的 Chrome (74.0.3729.157) 测试这个,还没有尝试过其他浏览器。

您需要等到元素被定义。

Custom​Element​Registry​.when​Defined()

The whenDefined() method of the CustomElementRegistry interface returns a Promise that resolves when the named element is defined.

customElements.whenDefined('test-case').then(
  () => {
    const test = document.getElementById("test");
    console.log(test.mood, test.constructor);
  }
);
<script type="module">
const template = document.createElement ( "template" );

template.innerHTML = "<span>Hello!</span>";

window.customElements.define ( "test-case",

class TestCase extends window.HTMLElement {
    constructor () {
        super ();
        
        var frag = template.content.cloneNode ( true ),
            shadow = this.attachShadow( { mode: "open" } );
        
        shadow.appendChild ( frag );
    }
    
    get mood () {
        return "Happy!";
    }
} );
</script>
<test-case id="test"></test-case>

您的 non-module 脚本在模块脚本之前 运行。所以你只需要等到元素被定义但调用 customElements.whenDefinedhttps://devdocs.io/dom/customelementregistry/whendefined

在使用 customElementsHTMLElement 时也没有理由使用 window

customElements.whenDefined('test-case').then(
  () => {
    const test = document.getElementById ( "test" );
    console.log ( test.mood, test.constructor );
  }
);
<script type="module">
const template = document.createElement ( "template" );
template.innerHTML = "<span>Hello!</span>";
customElements.define ( "test-case",
  class TestCase extends HTMLElement {
    constructor () {
      super ();
      const frag = template.content.cloneNode ( true );
      const shadow = this.attachShadow( { mode: "open" } );
      shadow.appendChild ( frag );
    }
    
    get mood () {
      return "Happy!";
    }
  }
);
</script>
<test-case id="test"></test-case>