Как использовать пользовательский элемент для переноса дочерних пользовательских элементов в div

Я пытаюсь создать пользовательский элемент-оболочку, который оборачивает свои дочерние пользовательские элементы в div.

Но дочерние элементы не завернуты. Вместо этого пустой элемент div вставляется в элемент-оболочку перед дочерними элементами.

<script>
  class ListItem extends HTMLElement {
    constructor() {
      super();
    }

    connectedCallback() {
      this.innerHTML = "<div>ListItem</div>";
    }
  }

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

    connectedCallback() {
      this.innerHTML = `<div class="list">${this.innerHTML}</div>`;
    }
  }

  customElements.define("list-item", ListItem);
  customElements.define("my-list", List);
</script>

<my-list>
  <list-item></list-item>
  <list-item></list-item>
  <list-item></list-item>
</my-list>

Вот результат:

<my-list>
  <div class="list"></div>
  <list-item><div>ListItem</div></list-item>
  <list-item><div>ListItem</div></list-item>
  <list-item><div>ListItem</div></list-item>
</my-list>

Я ожидал следующего:

<my-list>
  <div class="list">
    <list-item><div>ListItem</div></list-item>
    <list-item><div>ListItem</div></list-item>
    <list-item><div>ListItem</div></list-item>
  </div>
</my-list>

Вы можете попробовать его здесь.


person Lynbarry    schedule 25.01.2019    source источник
comment
Похоже, вы используете другую библиотеку или среду, отличную от простого JS. Какую библиотеку вы используете?   -  person Polyducks    schedule 25.01.2019
comment
Без использования какой-либо библиотеки, это просто JS Пользовательские элементы   -  person Lynbarry    schedule 25.01.2019
comment
Я предполагаю, что вы думаете, что:connectedCallback() { this.innerHTML = <div class="list">${this.innerHTML}</div>; } ..... Приведет ли элемент списка к списку div? и вы пытаетесь добиться этого, вызывая customElements.define(list-item, ListItem); непосредственно перед 'customElements.define (мой-список, список);' - Это было вашим намерением?   -  person Sparlarva    schedule 25.01.2019
comment
Спасибо @Lynbarry - мне нужно ознакомиться с синтаксисом класса!   -  person Polyducks    schedule 28.01.2019


Ответы (1)


Это связано с последовательностью выполнения синтаксического анализа. Когда тег <my-list> обнаружен, он создается (и подключается) немедленно, прежде чем будут вставлены его дочерние элементы.

В результате ${this.innerHTML} вернет пустую строку в connectedCallback().

Вы можете дождаться разбора дочерних элементов, например, с помощью setTimeout():

class List extends HTMLElement {
    connectedCallback() {
        setTimeout( () => 
            this.innerHTML = `<div class="list">${this.innerHTML}</div>` 
        )
    }
}

Но вам лучше использовать Shadow DOM с <slot> для вставки элементов светлого DOM:

class List extends HTMLElement {
    connectedCallback() {
        this.attachShadow( { mode: 'open' } )
            .innerHTML = `<div class="list"><slot></slot></div>` 
    }
}

См. пример ниже.

class ListItem extends HTMLElement {
    connectedCallback() {
        this.innerHTML = "<div>ListItem</div>";
    }
}

class List extends HTMLElement {
    connectedCallback() {
        this.attachShadow( { mode: 'open' } )
            .innerHTML = `<div class="list"><slot></slot></div>` 
    }
}

customElements.define("list-item", ListItem);
customElements.define("my-list", List);
<my-list>
    <list-item></list-item>
    <list-item></list-item>
    <list-item></list-item>
</my-list>

person Supersharp    schedule 25.01.2019
comment
Благодарю вас! Я пытался использовать только пользовательские элементы, потому что слышал, что Shadow Dom Polyfill, возможно, еще не готов. Впрочем, сейчас мы рассмотрим его более тщательно. - person Lynbarry; 28.01.2019
comment
@Lynbarry: Как разработчик и потребитель пользовательских элементов во всех его итерациях почти с самого начала, полифилл Shadow DOM довольно хорош. Справедливости ради, однако, если вам не нужно поддерживать IE11 (потенциально ниже), он вам даже не нужен. Мой опыт показывает, что загрузчик webcomponentsjs-loader является одним из лучших и достаточно хорошо работает, позволяя вашему коду работать достаточно согласованно в IE11, Chrome, Edge, Safari и Firefox. На самом деле, его использование избавляет от головной боли гораздо больше, чем его неиспользование. И, если вы его используете, у вас есть Shadow DOM. Намного лучше, чем Shady DOM, ИМХО. - person Fuzzical Logic; 01.02.2019