HTML导入加载订单怪癖?

时间:2017-05-27 12:54:58

标签: javascript html web-component custom-element html-imports

嘿!

我很难理解HTML Imports的特定行为。我只是在导入中交换一行并获得完全不同的输出。

所以这就是我得到的......

的index.html

<!DOCTYPE html>
<html>
<head>
    <link rel="import" href="./element-a.html">
    <link rel="import" href="./element-b.html">
    <link rel="import" href="./element-c.html">
</head>
<body>
    <element-a></element-a>
</body>
</html>

元素-a.html

<template>
    <element-b>
        <element-c>Hi!</element-c>
    </element-b>
</template>

<script>
console.log('registering a');

class ElementA extends HTMLElement {
    constructor() {
        super();

        console.log('upgrading a');

        const $template = this.constructor.ownerDocument.querySelector('template');
        const $clone = $template.content.cloneNode(true);

        this.attachShadow({ mode: 'open' });
        this.shadowRoot.appendChild($clone);

        const $c = this.shadowRoot.querySelector('element-c');
        const isDefined = () => console[$c.say ? 'debug' : 'error'](`say() is ${$c.say ? '': 'un'}defined`)

        isDefined();

        const undefined = this.shadowRoot.querySelectorAll(':not(:defined)');
        const promises = [...undefined].map(el => customElements.whenDefined(el.localName));

        console.log('undefined: ', undefined);

        Promise.all(promises).then(() => {
            console.log('ready');
            isDefined();
        });
    }
}

ElementA.ownerDocument = document.currentScript.ownerDocument;

customElements.define('element-a', ElementA);
</script>

元素-b.html

<template>
    <slot></slot>
</template>

<script>
console.log('registering b');

class ElementB extends HTMLElement {
    constructor() {
        super();

        console.log('upgrading b');

        const $template = this.constructor.ownerDocument.querySelector('template');
        const $clone = $template.content.cloneNode(true);

        this.attachShadow({ mode: 'open' });
        this.shadowRoot.appendChild($clone);
    }
}

ElementB.ownerDocument = document.currentScript.ownerDocument;

customElements.define('element-b', ElementB);
</script>

元素-c.html

<template>
    <slot></slot>
</template>

<script>
console.log('registering c');

class ElementC extends HTMLElement {
    constructor() {
        super();

        console.log('upgrading c');

        const $template = this.constructor.ownerDocument.querySelector('template');
        const $clone = $template.content.cloneNode(true);

        this.attachShadow({ mode: 'open' });
        this.shadowRoot.appendChild($clone);
    }

    say(words) {
        console.log(words);
    }
}

ElementC.ownerDocument = document.currentScript.ownerDocument;

customElements.define('element-c', ElementC);
</script>

我还创建了一个pen。现在令我困惑的是:如果我首先导入element-a ,我会得到此输出:

  

注册一个   升级   say()未定义
  undefined:(2)[element-b,element-c]
  注册b
  升级b
  注册c
  升级c
  准备
  say()已定义

但如果我最后导入它,我会得到一个完全不同的输出和注册升级的顺序。

  

注册b
  注册c
  注册   升级   升级b
  升级c
  说()是定义的   undefined:[]
  准备
  say()已定义

为什么?我有点期待最后的输出是总是发生的输出。它与插槽/ Shadow DOM有关吗?

1 个答案:

答案 0 :(得分:1)

您应该在element-a.html中导入element-a的依赖项。 HTMLImport导入并注册组件,这就是为什么你得到一些未定义的原因,因为在导入其他文件之前注册组件(导入是异步的)。在注册组件之前,浏览器会在元素内部导入依赖项,直到所有依赖项都准备就绪。

您可以阅读有关Managing dependencies and sub-imports

的更多信息