修改 shadow root 中自定义元素的样式

问题描述 投票:0回答:2

我正在尝试使用影子 DOM 修改两个自定义 HTML 元素“输出屏幕”和“自定义计算器”的样式。

当我尝试通过附加影子 DOM 来实现时,如下所示,样式未应用。知道我做错了什么吗?

JS 小提琴

<custom-calculator id="calculator">
  <output-screen></output-screen>
</custom-calculator>

<script>
var o = Object.create(HTMLElement.prototype);
    var oElement = document.registerElement('output-screen', {
        prototype: o
    });

var c = Object.create(HTMLElement.prototype);
var cElement = document.registerElement('custom-calculator', {
  prototype: c
});

var calc = document.querySelector('#calculator')
calc.attachShadow({ mode: 'open' });
calc.shadowRoot;
calc.shadowRoot.innerHTML = `
<style>
output-screen{
display:inline-block;
background-color:orange;
width:50%;
height:100vh;
}
custom-calculator {
display:inline-block;
background-color:grey;
width:100%;
height:100vh;
vertical-align:top;
}
</style>
`;
</script>
javascript html css shadow-dom custom-element
2个回答
6
投票

为了设置托管 Shadow DOM 的元素的样式,在这里

<custom-calculator>
,您必须使用 de
:host
伪类(而不是 Shadow DOM 中未知的
custom-calculator
)。

:host {
  display:inline-block;
  background-color:grey;
  width:100%;
  height:100vh;
  vertical-align:top;
}

因为 Shadow DOM 将替换/恢复普通的 DOM 树(这里是

<output-screen>
),你必须使用
<slot>
来插入/显示它到 Shadow DOM 中。

calc.shadowRoot.innerHTML = `
  <style>
    ...
  </style>
  <slot></slot>`

然后,为了设置

<slot>
元素显示的内容的样式,您必须使用
::slotted()
伪元素:

::slotted( output-screen ){
  display:inline-block;
  background-color:orange;
  width:50%;
  height:100vh;
}

实例:

var calc = document.querySelector('#calculator')
calc.attachShadow({mode: 'open'});
calc.shadowRoot.innerHTML = `
  <style>
    :host {
      display:inline-block;
      background-color:grey;
      width:100%;
      height:100vh;
      vertical-align:top;
    }

    ::slotted( output-screen ){
      display:inline-block;
      background-color:orange;
      width:50%;
      height:100vh;
    }
  </style>
  <slot></slot>`;
<custom-calculator id="calculator">
  <output-screen></output-screen>
</custom-calculator>


0
投票

在使用 自定义元素 时,您绝对应该使用类语法,因为它会使事情变得更清晰。

这是根据您提供的代码逐步进行的工作改编:

1。字符串模板:
您需要做的第一件事是定义您将使用的模板。

const string_templates = {
    "custom-calculator": `<style>
      :host {
        display: inline-block;
        background-color: grey;
        width: 100%;
        height: 100vh;
        vertical-align: top;
      }
    </style>
    <slot></slot>`, // !! slot !!
    "output-screen": `<style>
      :host {
        display: inline-block;
        background-color: orange;
        width: 50%;
        height: 100vh;
      }
    </style>`
};

这里我们声明一个关联数组,它以

"key":'value'
格式存储条目。我们有两个条目,它们的键是
"custom-calculator"
"output-screen"
,每个条目都将与其关联的模板存储为字符串值。

由于

<custom-calculator>
element将在其html标签中接收其他
HTMLElement
我们需要在其模板中添加
<slot>element
<slot>
elementtemplate 中的位置定义了
<custom-selector>
tags 中提供的 html 代码将在该 elementrendered

2。从字符串模板创建最终模板:
这些模板将在创建新的自定义元素实例时使用。

const calc_template = document.createElement('template'); // creates a new <template> element
calc_template.innerHTML = string_templates["custom-calculator"]; // parse the string template only one time

const out_template = document.createElement('template');
out_template.innerHTML = string_templates["output-screen"];

这里我们定义了两个常量

calc_template
out_template
,每个常量都用一个新的空
<template>
element初始化,然后添加相关的字符串模板作为它们的
innerHTML
value

在类之外执行此操作允许在文件运行时仅解析一次模板。

3。 “CustomCalculator”和“OutputScreen”类:
这里使用的类非常简单,因为它们只包含一个执行以下操作的构造函数:

  • 调用 super() 这是 mandatory 在使用
    this
    之前,因为该类是 derived(扩展另一个类)否则会出现引用错误。
  • 使用 Element.attachShadow() 将带有 shadow DOMshadowRoot 附加到 element
  • 克隆关联的templatecontent并将其附加为elementshadow DOMchildElement.appendChild()

-自定义计算器类:

// Class for the <custom-calculator> customElement
class CustomCalculator extends HTMLElement {
  constructor() {
    super(); // always call super() first
    this.shadow = this.attachShadow( { mode:'open'} ); // attach a shadowRoot to the element
    // clone a template content and add the clone as a shadow DOM child (no <template> tags)
    this.shadow.appendChild( calc_template.content.cloneNode(true) ); 
  } 
} //

注意:如果您想从

<output-screen>
class中检索
CustomCalculator
element,您将不得不使用
this.querySelector()
而不是
this.shadow.querySelector()
,因为html内容提供给通过 <slot>
 的自定义元素
不是此 elementshadow DOM 的一部分,而是位于其 light DOM 内。 (使用页面检查器检查)

- OutputScreen 类:

// Class for the <output-screen> customElement
class OutputScreen extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow( {mode:'open'} );
    this.shadow.appendChild( out_template.content.cloneNode(true) );
  } 
} //

4。注册自定义元素:
当定义用于自定义元素模板时,我们可以使用customElements.define().register

它们

注意:一旦在页面中定义了一个自定义元素tag,它就不能再与另一个class一起使用,所以如果你想使用两个具有相同tag自定义元素你将不得不改变其中之一。

customElements.define( 'custom-calculator', CustomCalculator ); // register the <custom-calculator> customElement
customElements.define( 'output-screen', OutputScreen ); // register the <output-screen> customElement

不要忘记指令第一部分末尾的“s”,这是错误的来源。

© www.soinside.com 2019 - 2024. All rights reserved.