HTML自定义元素子容器

时间:2018-11-13 01:47:10

标签: javascript web-component

我试图制作一个经典的菜单栏,并同时使用Web组件。我从没和他们玩过,这是我第一次涉足这个领域。它们似乎是一个非常强大的工具,但是关于我正在尝试做的事情似乎没有太多可用信息。

我有一棵自定义html元素的树,当前看起来像这样(在调用构造函数之后):

<menu-bar>
  <sub-menu label="some label">
    <label>some label</label>
    <menu-item></menu-item>
    <menu-item></menu-item>
    <menu-item></menu-item>
  </sub-menu>
</menu-bar>

如何使自定义元素将其变成...

<menu-bar>
  <sub-menu label="some label">
    <label>some label</label>
    <div>
      <menu-item></menu-item>
      <menu-item></menu-item>
      <menu-item></menu-item>
    </div>
  </sub-menu>
</menu-bar>

...何时调用子菜单的构造函数?还有可能使div成为影子dom的一部分,而菜单项元素不在影子dom中吗?

相关示例代码

class MenuBar extends HTMLElement {
  constructor() {
    super();
  }
};

class SubMenu extends HTMLElement {
  constructor() {
    super();
    let shadowRoot = this.attachShadow({mode: "open"});
    this.labelElement = document.createElement("label");
    shadowRoot.appendChild(this.labelElement);
  }

  static get observedAttributes() {
    return ["label"];
  }
  attributeChangedCallback(pName, pOldValue, pNewValue) {
    switch (pName) {
      case "label":
        this.labelElement.innerHTML = pNewValue;
        break;
    }
  }
};

class MenuItem extends HTMLElement {
  constructor() {
    super();
  }
};

window.customElements.define("menu-bar", MenuBar);
window.customElements.define("sub-menu", SubMenu);
window.customElements.define("menu-item", MenuItem);

任何帮助都将不胜感激,因为我正在学习这些功能的工作原理,并且正在寻找更多有关使用Web组件操作预定义html的细节的信息,而不只是直接回答此确切示例本身。

1 个答案:

答案 0 :(得分:2)

您需要使用<slot>来允许非shadowDOM子级显示在元素的shadowDOM中。

示例:

class MenuBar extends HTMLElement {
  constructor() {
    super();
  }
};

class SubMenu extends HTMLElement {
  constructor() {
    super();
    let shadowRoot = this.attachShadow({mode: "open"});
    this.labelElement = document.createElement("label");
    let temp = document.createElement("div");
    temp.innerHTML = '<slot></slot>';
    shadowRoot.appendChild(this.labelElement);
    shadowRoot.appendChild(temp);
  }

  static get observedAttributes() {
    return ["label"];
  }
  attributeChangedCallback(pName, pOldValue, pNewValue) {
    switch (pName) {
      case "label":
        this.labelElement.innerHTML = pNewValue;
        break;
    }
  }
};

class MenuItem extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({mode: "open"}).innerHTML = `
    <style>
    :host {
      background-color: #eee;
      border: 1px solid #ddd;
      display:block;
      margin: 1px 0;
    }
    </style>
    <slot></slot>
    `;
  }
};

window.customElements.define("menu-bar", MenuBar);
window.customElements.define("sub-menu", SubMenu);
window.customElements.define("menu-item", MenuItem);
<menu-bar>
  <sub-menu label="some label">
    <menu-item>1</menu-item>
    <menu-item>2</menu-item>
    <menu-item>3</menu-item>
  </sub-menu>
</menu-bar>

在您的SubMenu中,我在<div>上添加了<slot>,以容纳所有<menu-item>组件。

我还添加了一些次要CSS,以便于查看子元素。