HTML Пользовательский Элемент Дочерний Контейнер - PullRequest
0 голосов
/ 13 ноября 2018

Я пытаюсь создать классическую строку меню и одновременно играть с веб-компонентами. Я никогда не играл с ними, и это мой первый набег в тему. Они кажутся довольно мощным инструментом, но, похоже, мало информации о том, что я пытаюсь сделать.

У меня есть дерево пользовательских 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 частью теневого домена без элементов меню, находящихся в теневом домике?

Соответствующий образец кода

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);

Любая помощь очень ценится, так как я только изучаю, как они работают, и ищу больше подробностей о том, как манипулирование предопределенным HTML с помощью веб-компонентов будет работать больше, чем просто прямой ответ на этот конкретный пример как таковой.

1 Ответ

0 голосов
/ 13 ноября 2018

Вам нужно использовать <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, чтобы было легче видеть подэлементы.

...