2017-07-12 119 views
1

我有一個自定義元素(沒有陰影DOM),我希望能夠在任何地方使用,即使在另一個可能使用陰影DOM的自定義元素。但是,我不確定如何讓樣式在這兩個地方工作。在陰影內部和外部使用非陰影DOM自定義元素

例如,可以說我創建一個簡單的fancy-button元素:

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

 
    this.innerHTML = ` 
 
     <style> 
 
     fancy-button button { 
 
     padding: 10px 15px; 
 
     background: rgb(62,118,194); 
 
     color: white; 
 
     border: none; 
 
     border-radius: 4px 
 
     } 
 
     </style> 
 
     <button>Click Me</button>`; 
 
    } 
 
} 
 

 
customElements.define('fancy-button', fancyButton);
<fancy-button></fancy-button>

內陰影DOM元素,插入式的標籤將允許fancy-button樣式工作。但是,如果此組件在陰影DOM元素外部使用,則每次使用該元素時,樣式標記都將被複制。

如果我將style標籤添加爲html導入文件的一部分,那麼這些樣式只能在陰影DOM之外工作,但至少它們只會聲明一次。

<!-- fancy-button.html --> 
<style> 
fancy-button button { 
    padding: 10px 15px; 
    background: rgb(62,118,194); 
    color: white; 
    border: none; 
    border-radius: 4px 
} 
</style> 

<script> 
class fancyButton extends HTMLElement { 
    constructor() { 
    super(); 

    this.innerHTML = `<button>Click Me</button>`; 
    } 
} 

customElements.define('fancy-button', fancyButton); 
</script> 

什麼是最好的方式來添加自定義元素樣式處理在陰影DOM內部和外部使用?

+1

最好的方法是第一個解決方案,因爲它是唯一可行的解​​決方案。另一種方法是測試你是否在Shadow DOM中,然後根據需要添加樣式。 – Supersharp

回答

1

所以我能夠找到一個解決方案,感謝Supersharp關於檢查我們是否在陰影DOM中的建議。

首先,您將樣式添加爲導入文件的一部分,以便樣式默認情況下應用於陰影DOM之外。然後,當將元素添加到DOM時,我們檢查getRootNode()以查看它是否已添加到ShadowRoot節點。如果有,並且樣式尚未被注入到根中,那麼我們可以手動注入樣式。

var div = document.createElement('div'); 
 
var shadow = div.attachShadow({mode: 'open'}); 
 
shadow.innerHTML = '<fancy-button></fancy-button>'; 
 

 
document.body.appendChild(div);
<style data-fs-dialog> 
 
    fancy-button button { 
 
    padding: 10px 15px; 
 
    background: rgb(62,118,194); 
 
    color: white; 
 
    border: none; 
 
    border-radius: 4px 
 
    } 
 
</style> 
 

 
<script> 
 
class fancyButton extends HTMLElement { 
 
    constructor() { 
 
    super(); 
 
    } 
 
    
 
    connectedCallback() { 
 
    this.innerHTML = `<button>Click Me</button>`; 
 
    
 
    var root = this.getRootNode(); 
 

 
    // In polyfilled browsers there is no shadow DOM so global styles still style 
 
    // the "fake" shadow DOM. We need to test for truly native support so we know 
 
    // when to inject styles into the shadow dom. The best way I've found to do that 
 
    // is to test the toString output of a shadowroot since `instanceof ShadowRoot` 
 
    // returns true when it's just a document-fragment in polyfilled browsers 
 
    if (root.toString() === '[object ShadowRoot]' && !root.querySelector('style[data-fs-dialog]')) { 
 
     var styles = document.querySelector('style[data-fs-dialog]').cloneNode(true); 
 
     root.appendChild(styles); 
 
    } 
 
    } 
 
} 
 

 
customElements.define('fancy-button', fancyButton); 
 
</script> 
 

 
<fancy-button></fancy-button>

當所有瀏覽器支持<link rel=stylesheet>在影子DOM,則聯腳本可以變成外部樣式表作爲robdodson建議,以及將碼是有點清潔器。

1

您可能想要將樣式放在一個單獨的CSS文件中,該文件與您的元素的JS一起出售。但正如你指出的那樣,如果你把元素放在另一個元素的Shadow DOM中,那麼這些樣式將不能在該範圍內工作。出於這個原因,通常最好只創建一個影子根,並在其中彈出你的樣式。任何你不想這樣做的理由?

+0

大多數情況下,這是一個深入的實驗,看看您是否可以創建自定義元素,而不需要可以共享的影子DOM(因爲它們更容易覆蓋不需要css變量的樣式)。但是,如果對元素進行樣式化需要陰影DOM,所以它在陰影DOM中工作,那麼我不確定何時要編寫一個非陰影DOM可共享元素,這看起來很不幸。 –