2017-05-27 73 views
1

嘿!HTML導入加載命令的怪癖?

我很難理解HTML導入的特定行爲。我只是在進口內交換一行並獲得完全不同的輸出。

因此,這裏是我得到了什麼?

的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第一我得到這樣的輸出:

註冊
升級
說()是未定義
未定義:(2)[元素B,元素 - C]
註冊b
升級b
註冊ç
升級ç
準備
說()被定義

但是,如果我在最後導入它,我得到一個完全不同的註冊升級的輸出和秩序。

註冊b
註冊Ç
登記
升級
升級b
升級Ç
說()被定義
未定義:[]
準備
說()是定義爲

這是爲什麼?我期望最後的輸出是始終發生的輸出。它與插槽/ Shadow DOM有什麼關係?

+0

從https://w3c.github.io/webcomponents/spec/custom/#upgrades:請注意,只升級適用於文檔樹中的元素。未插入到文檔中的元素將保持未升級狀態。因此,在第二個示例中,它們都是首先註冊的,因爲「A」尚未出現在文檔中。 – ebidel

+0

我明白了,但是我不明白導入的順序與此有關?特別是因爲在這兩種情況下'element-a'始終在文檔樹中。 – mzdr

+1

'element-a'在開始的文檔中,但是'b'和'c'不是(直到'a'被註冊)。這兩個人立即註冊b/c你正在加載他們的進口。但只有在'a'導入將它們添加到文檔中時纔會升級它們。合理? – ebidel

回答

1

您應該在element-a.html中導入element-a的依賴關係。 HTMLImport導入並註冊組件,這就是爲什麼你得到一些未定義的原因,因爲在導入其他文件(導入是異步)之前註冊組件。在註冊組件之前,瀏覽器等待所有依賴項準備就緒,然後導入元素內的依賴項。

你可以閱讀更多關於Managing dependencies and sub-imports

+2

您應該嘗試管理組件導入中需要它們的代碼。但是,缺省情況下,導入不是異步的,並且瀏覽器不會等到所有導入都在註冊元素之前加載。我相信這是一個聚合物1.0的事情。 – ebidel