[英]Why does my shadow dom break my custom element?
這是自定義元素的 JSFiddle 演示: https ://jsfiddle.net/c4bLo097/5/
這是小提琴中的代碼:
JavaScript:
window.customElements.define('test-element', class TestElement extends HTMLElement {
constructor() {
super()
let contents = `
<style>
:host {
display: block;
}
:host([hidden]) {
display: none;
}
</style>`
// convert string to nodes
let template = document.createElement('template')
template.innerHTML = contents
// create shadow
this.attachShadow({mode: 'open'})
// insert nodes
this.shadowRoot.appendChild(template.content.cloneNode(true))
}
})
HTML:
<test-element>
This element should have a natural height.
<div style="height: 300px;"></div>
I should be able to see this text on a green background.
</test-element>
CSS:
test-element {
width: 200px;
background: green;
}
如果您使用開發人員工具檢查<custom-element>
,您應該會看到陰影在那里。 但是我的元素不會正確呈現其高度。
這是我試圖實現的一個示例 JSFiddle: https ://jsfiddle.net/9483s1qb/2/
當您添加 shadowDOM 時,元素的內容將變為“lightDOM”。
它不再顯示在主 DOM 中,也不是 shadowDOM 的一部分。
Light DOM 只是 HTML 元素內的普通舊 DOM 樹。
該術語僅用於 Web 組件(帶有 Shadow DOM 的自定義元素)的上下文中
我想與Shadow相比,普通 DOM 被重新定義為Light 。WHATWG 規范將其稱為 shadowroot 主機的節點樹或光樹:
customElements.define('my-element', class extends HTMLElement { constructor() { //create shadowDOM (thus creating lightDOM) and append Template super() /* return this */ .attachShadow({mode: 'open'}) /* SETs and RETURNs this.shadowRoot */ .append(document.getElementById(this.nodeName).content.cloneNode(true)) } connectedCallback(){ //append content from lightDOM this.shadowRoot.append(...this.querySelectorAll('DIV')); } })
my-element{ border: 1px dashed blue; }
<template id="MY-ELEMENT"> <style> :host { display: block; font-size:20px; } h4{ background:yellow; margin: .5em 0; } div{ background:lightcoral; } </style> <h4><slot name="title"></slot></h4> </template> <my-element> <!-- begin lightDOM because my-element has shadowDOM --> <span slot="title">whole SPAN is slotted</span> <div>I am appended</div> <div>appended too</div> <p>I remain (invisible) in lightDOM</p> <!-- end lightDOM --> </my-element> <my-element> <!-- begin lightDOM because my-element has shadowDOM --> <span slot="title">slotted too</span> <div>appended again</div> I remain (invisible) in lightDOM <!-- end lightDOM --> </my-element>
片段注釋:
模板被克隆
connectedCallback
的append移動內容,
如果您想將原始文件保留在 lightDOM 中(例如,將其用作數據存儲)
你必須像使用template
一樣克隆它。
slot="title"
將整個span
(包括跨度!)反映到它在 shadowDOM 中的插槽中
請參閱:::slotted CSS 選擇器用於 shadowDOM 插槽中的嵌套子項
自己試試:
在 JSFiddle 游樂場: https ://jsfiddle.net/CustomElementsExamples/bzvLcxfe/
未命名的: <slot></slot>
什么?
如果將<span>
更改為<div>
會發生什么
當(主)DOM 尚未實例化時,您可能需要在connectedCallback
使用setTimeout
:
connectedCallback() {
let savedHTML = this.outerHTML;
//append content from lightDOM
const append = (selector) =>
this.shadowRoot.append(...this.querySelectorAll(selector), savedHTML);
if (this.outerHTML.includes("timeout"))
setTimeout(() => append('DIV'))
else
append('DIV');
}
JSFiddle 游樂場: https ://jsfiddle.net/CustomElementsExamples/bzvLcxfe/
在第一個黃色元素 DIV 中附加沒有setTimeout
在第二黃色元素的DIV附加有一個setTimeout
兩個元素中都附加了outerHTML
(在connectedCallback
已知)。
setTimeout
需要延遲代碼直到事件循環完成,並且 lightDOM 可用。setTimeout
需要 當customElements.define
在DOM 准備好之前運行時(在 Chromium 瀏覽器中)會發生這種情況。 如果在創建 DOM 元素后更改JSFiddle並執行<script>
塊,則一切正常。
(但大多數情況下,您會盡快加載庫以防止FOUC
connectedCallback
中的requestAnimationFrame
connectedCallback
setTimeout
具有相同的行為。 更多詳情: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
當您加載內容異步的DOM也可能准備<script src=elements.js async ></script>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.