我正在使用 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);
constructor
结论,你不能在那里添加 DOM-1 对于您的
connectedCallback
结论,它不会在创建 DOM 之后触发。
connectedCallback
在 opening标签
<my-button>
上触发。如需详细阅读,请参阅我的博文:Web 组件开发人员尚未与连接回调连接
新的 lightDOM(您的button
代码)又
读取现有的 lightDOM(您的
firstChild
)您的create
,如果你想要 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>