如何动态设置 Web 组件的属性

How To Set An Attribute Of A Web Component Dynamically

我一直在尝试为我设计的名为 ws-dialog 的自定义 Web 组件设置属性。它总是在代码上添加一个属性undefined

<ws-dialog class="global" undefined="add-page-content"></ws-dialog>

我想在这里做的是声明一个像template这样的属性,而不是undefined。这是我用于向所有对话目标元素添加 onclick 事件的代码:

function addDialogEvents(target) {
    target.addEventListener("click", () => {
        let dialog = document.createElement(Dialog.getName());
        let body = document.querySelector("body");

        dialog.template = "add-page-content";

        body.append(dialog);
});

}

这是我的自定义组件的代码:

"use strict";


class Dialog extends HTMLElement {


    connectedCallback() {
        //Styles for this custom component are declared in a separate CSS module
    }


    updateContent(id) {
        let content = document.querySelector(`template#${id}`).content;

        if (content)
            this.append(content);
    }


    attributeChangedCallback(name, oldValue, newValue) {
        this.TEMPLATE = "template";

        switch (name) {
            case this.TEMPLATE:
                this.updateContent(newValue);
                break;
        }
    }


    static get observedAttributes() {
        return [this.TEMPLATE];
    }


    static getName() {
        return "ws-dialog";
    }


    get template() {
        return this.getAttribute(this.TEMPLATE);
    }


    set template(template) {
        this.setAttribute(this.TEMPLATE, template);
    }

}



customElements.define(Dialog.getName(), Dialog);

这里有一个 playground,可以帮助您了解什么时候触发了什么方法。

注意何时 以及调用了多少次 observedAttributes
这意味着您的 this.TEMPLATEundefined,因此成为 Array

中的字符串 undefined

<script>
  const log = (...args) => {
    let div=document.body.appendChild(document.createElement('DIV'));
    div.style = `background:${args.shift()};color:white;font:13px Arial`;
    div.append(args.join(" "));
  }
  customElements.define('my-element', class extends HTMLElement {
    log() {
      log(this.getAttribute("color"), this.outerHTML.split(">")[0],'>', ...arguments);
    }
    static get observedAttributes() {
      log('red', `my-element observedAttributes`);// NO 'this' / Element here!
      return ["color"];
    }
    constructor() { super().log("constructor") }
    connectedCallback() {
      this.log("connectedCallback" , this.innerHTML || "No innerHTML" );//FireFox difference!
      setTimeout(() => this.log(`delayed connectedCallback ${this.innerHTML}`), 0);
    }
    attributeChangedCallback(name, oldValue, newValue) { // 4th W3C parameter = Namespace (not implemented in Browsers)
      this.log("attributeChangedCallback", name, oldValue || "null", newValue);
    }
    disconnectedCallback(){ this.log("disconnectedCallback") }
  })
  document.body.onload = () => {
    log('magenta', 'onload event');
    A.setAttribute("color", "darkolivegreen");
    B.innerHTML = "<my-element id=C color=hotpink>Charlie replaced Bravo</my-element>";
    B.remove();
  }
</script>
<my-element id=A color=green>Alfa</my-element>
<my-element id=B color=blue>Bravo</my-element>

备注:

  • 有用的图表位于:https://andyogo.github.io/custom-element-reactions-diagram/

  • 仅在 FireFox 中执行顺序略有不同,我的建议是不要开发,仅在 Firefox 中测试

  • 在 FireFox 中,您可以从 connectedCallback 访问内部元素。在所有其他浏览器中,您需要 setTimeout。同一 W3C 标准的不同技术解释。在这种情况下,Apple 工程师是正确的 source。 Chromium 基于相同的引擎。

  • 请注意 C connectedCallback(或任何方法)中的(延迟)代码如何运行 AFTER disconnectedCallback.
    您需要编写在 DOM 元素不再存在时不会出错的代码。


JSFiddle 操场:https://jsfiddle.net/CustomElementsExamples/n20bwckt/