如何在connectedCallback之前但构造函数之后渲染我的Web组件?

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

我正在使用 vanilla JavaScript 制作自定义 Web 组件,并且在何时呈现该组件方面遇到一些问题。

首先,我在组件的构造函数内进行了

render()
hydrate()
调用。当组件一开始就已经是 DOM 的一部分时,这种方法效果很好,但是,如果组件是使用
document.createElement("my-button")
创建的,那么
render()
调用最终会在我有机会添加属性和子元素之前执行等等。这是一个大问题。

另一种选择,即我下面的代码所示,是在

render()
方法内调用
hydrate()
connectedCallback()
。这解决了
document.createElement("my-button")
问题,但是,它引入了一个新问题。因为
connectedCallback()
仅在将元素添加到 DOM 后执行 ,所以我可能会在组件完成渲染之前获得 FOUC(无样式内容的 Flash)。如果有一个
beforeConnectedCallback()
就好了,这样我就可以在将其添加到 DOM 之前执行代码,但这似乎不存在。

那么我应该怎么做才能让我的组件在添加到 DOM 之前自动渲染和水化呢?

这是我的组件:

class MYButton extends HTMLElement { constructor() { super(); } connectedCallback() { this.render(); this.hydrate(); } render() { let type = this.getAttribute("type"); if (type === "link") { this.elmButton = document.createElement("a"); this.elmButton.setAttribute("href", this.getAttribute("href")); } else { this.elmButton = document.createElement("button"); this.elmButton.setAttribute("type", type); } while (this.firstChild) { this.elmButton.appendChild(this.firstChild); } this.appendChild(this.elmButton); } hydrate() { this.elmButton.addEventListener("click", () => alert("hello world")); } } customElements.define('my-button', MYButton);
    
javascript web-component
1个回答
0
投票
+1 为你的

constructor

 结论,你不能在那里添加 DOM 

-1 对于您的

connectedCallback

 结论,它不会在 
创建 DOM 之后触发。 connectedCallback
opening
标签 <my-button> 上触发。
如需详细阅读,请参阅我的博文:
Web 组件开发人员尚未与连接回调连接
Web 组件面临的挑战是,您既想

创建

新的 lightDOM(您的button代码)又

读取
现有的 lightDOM(您的firstChild
您的 
create
after read 非常好,否则您将无休止地添加该新按钮。 但总会有 FOUC/布局转变,因为

鱼与熊掌不可兼得

,如果你想要 lightDOM,你将不得不等待。 但是您可以让 Web 组件成为

hidden

并在所有工作完成后显示它,或者自己添加一个奇特的不透明过渡。

如果没有 

render

hydrate
mumbo-jumbo
,Web 组件是:

createElement = (tag, props = {}) => Object.assign(document.createElement(tag), props); customElements.define("my-button", class extends HTMLElement { connectedCallback() { this.setAttribute("hidden", true); setTimeout(() => { // wait for lightDOM to be parsed let type = this.getAttribute("type"); let [el, attr] = (type == "link") ? ["a", "href"] : ["button", "type"]; let button = createElement(el, { [attr]: this.getAttribute(attr), onclick: (evt) => alert(`Hello Web Components ${type} World!`) }); // .children will not include textNodes, all Nodes are *moved* button.append(...this.childNodes); this.append(button); this.removeAttribute("hidden"); }); } });
<style>
  [type="link"] {
    display: inline-block;
    background: pink;
    padding: 1em;
  }
</style>

<my-button>
  I am the button Label
  <div style="font-size:60px">😃</div>
</my-button>

<my-button type="link">
  Another label
  <div style="font-size:60px">🔗</div>
</my-button>

如果您确实想在

constructor

之后和

connectedCallback
之前执行,您可以
ABUSE
attributeChangedCallback 因为这会在
ObservedAttribute
声明的 every 上触发
before connectedCallback 会触发
<my-button>
开始标签。
但!你的 
<my-button>
中的 lightDOM 还没有被解析。

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