【问题标题】:Clarification regarding this.attachShadow({mode: 'open'}) and this.shadowRoot关于 this.attachShadow({mode: 'open'}) 和 this.shadowRoot 的说明
【发布时间】:2021-10-11 23:31:01
【问题描述】:

关于原生WebComponents:

class 开头的constructor() 方法中,通常会将影子DOM 树附加到Custom Element 并返回对其ShadowRoot 的引用:

class myCustomElement extends HTMLElement {

  constructor() {
    super();
    const shadowroot = this.attachShadow({mode: 'open'});
  }

 [... REST OF CODE HERE...]

}

引用的名称当然可以是任何东西

我见过:

  • var shadow = this.attachShadow({mode: 'open'});(见:Element.attachShadow()
  • this.root = this.attachShadow({mode: 'open'});

我们可以很容易地使用:

  • const myShadowRootzzz = this.attachShadow({mode: 'open'});

但是,已经存在Element.shadowRoot,这ShadowRoot参考。

那么为什么是语法

const shadow = this.attachShadow({mode: 'open'});

在示例中如此常用,简单说明时:

this.attachShadow({mode: 'open'});

就足够了,因为...任何时候需要引用ShadowRoot,该引用实际上是:

this.shadowRoot 

为什么 WebComponent 的 ShadowRoot 需要 另一个 超出 this.shadowRoot 的任意引用?

我是否遗漏了一些重要的东西...或者我可以安全地在我自己的WebComponents 中省略这些额外的引用吗?

【问题讨论】:

  • 我突然想到,如果可以将单个CustomElement 赋予多个 ShadowRoots,那么像const shadowroot1 = this.attachShadow({mode: 'open'}); 这样的引用会有意义。似乎在某一时刻(很久以前)这可能的,尽管the idea of multiple ShadowRoots was ditched in 2015,早在 WebComponents v1 在 2018 年底实现主流浏览器采用之前。后来,在 2019 年,@ 987654324@,但几乎没有得到浏览器供应商的支持。
  • 所以,除非我错过了什么,否则在 2021 年 CustomElement 只能有 一个 ShadowRoot。您可以选择给这个ShadowRoot 一个参考名称,如果您这样做,该参考名称可以是您想要的任何名称。 但是你给它取什么名字并不重要,因为你选择的任何东西都只会是this.shadowRoot别名。所以你不妨使用this.shadowRoot

标签: web-component shadow-dom custom-element native-web-component


【解决方案1】:

这是一个很好的例子,早期的代码/博客设置了错误的例子,
然后每个 Web 组件新手都会盲目地复制/粘贴。

即使是 MDN 文档也有错误:首先使用 super()

这是一个完全有效的构造函数:

constructor() {
    let myP = document.createElement("p");
    let myText = document.createTextNode("my text");
    myP.append(myText);
    // MDN docs are wrong, you can put code *before* super, 
    // you just can't reference 'this' *before* it is created
    super() // create and return 'this'
        .attachShadow({ mode: "open" }) // create and return this.shadowRoot
        .append(myP);
  }

【讨论】:

  • 这很有帮助,丹尼,谢谢。 +1它并没有真正回答我关于声明对this.shadowRoot 的额外任意引用的问题。 ;-)
  • let d = document 这样做有什么意义?
  • 我不知道。如果我们已经可以引用document.bodydocument.querySelector(),那么声明const d = document; 然后引用d.bodyd.querySelector() 的意义何在?这就是为什么我想知道我是否会遗漏一些重要的东西。
  • document和shadowroot有区别吗?
  • 使用自己/额外引用的一个正当理由是减慢代码执行速度....但这是我能想到的唯一“重要”应用程序 :-)
【解决方案2】:

所以有一个局部变量的一个很好的理由是当人们检查一个声明性的影子根时。

class MyElement extends HTMLElement {
  constructor() {
    super();
    let internals = this.attachInternals();
    let shadow = internals.shadowRoot;

    //No declarative shadow root define, so attach
    if (!shadow) shadow = this.attachShadow({ mode: 'open' });

    shadow.addEventListener('slotchange', this.handleSlotChanged);
  }

  connectedCallback() {
    //Load template & content into shadowroot
  }

  handleSlotChanged(e) {
    //handle changes when slot changes
  }
}

customElements.define('my-element', MyElement);
<my-element>
  <template>
    <p>Nothing happens - no code to generate template</p>
  </template>
</my-element>
<my-element>
  <template shadowRoot="open">
    <p>Automatically generated due to declarative shadow root</p>
   </template>
</my-element>

本地的“shadow”变量被赋值为“internals.shadowRoot”,但是如果模板没有声明性的影子根,那将是空的,所以用正常的方式分配它。

最后,对于这两种情况,无论“影子”来自何处,都可以对它做一些事情,例如附加一些事件处理程序...

所以可以在最后一点使用 this.shadowRoot,但是如果 this.shadowRoot 是一个属性,它会带来一些额外的开销。还有,真的和“internals.shadowRoot”一样吗?

【讨论】:

    猜你喜欢
    • 2012-03-24
    • 2017-06-18
    • 2016-03-24
    • 1970-01-01
    • 2019-08-29
    • 2019-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多