1

嘿!

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

所以这就是我得到的……</p>

索引.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>

我还制作了一支钢笔。现在让我感到困惑的是:如果我element-a 导入,我会得到以下输出:

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

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

注册 b
注册 c
注册 a
升级 a
升级 b
升级 c
say() 已定义
undefined: []
ready
say() 已定义

这是为什么?我有点希望最后一个输出总是会发生。它与 slotting/Shadow DOM 有关吗?

4

1 回答 1

1

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

您可以阅读有关管理依赖项和子导入的更多信息

于 2017-05-29T07:09:32.703 回答