Как добавить дочерние слоты в тег HTML для абсолютного позиционирования? - PullRequest
0 голосов
/ 23 мая 2019

Я создаю веб-компонент выпадающего меню, который будет использоваться такими пользователями, как:

<custom-menu>
    <custom-menu-anchor>
        <button>Toggle Menu</button>
    </custom-menu-anchor>

    <custom-menu-item>Fish</custom-menu-item>
    <custom-menu-item>
        <custom-icon name="chicken"/>
        <span>Chicken</span>
    </custom-menu-item>
</custom-menu>

Здесь элементы слотов типа <custom-menu-items> должны быть абсолютно позиционированы.

Для этого нам нужно

  1. Создать наложение
  2. Удалить элементы слота из веб-компонента
  3. Прикрепите их к элементу наложения.
  4. Обеспечить правильное позиционирование

Чтобы настроить идеальное наложение, мне нужно создать элемент overlay/surface, удалить дочерние элементы custom-menu-item и добавить их все к элементу наложения.

Чтобы добиться этого, я попытался сделать что-то подобное ниже в connectedCallback методе жизненного цикла:

const slot = this.shadowRoot.querySelector('slot');
const surface = document.createElement('div');

const nodes = slot.assignedNodes();

surface.append(...nodes);
document.body.appendChild(surface);

Проблемы с этим подходом:

  • Я заметил, что удаление assignedNodes из слота испортило много вещей.
  • Многие вещи не работают, когда я пытаюсь переместить слот lightDOM
  • slotchange не работает после перемещения элементов.
  • Кроме того, веб-компонент может использоваться в любой среде, это может быть lit-html, Vue или даже простой JavaScript. Я заметил, что после перемещения этих элементов DOM это начинает нарушать абстракции пользовательских библиотек.

Эта потребность применяется к любым абсолютно позиционированным / смещенным компонентам, таким как уведомление, диалог, выпадающий список, Snackbar и вышеуказанный подход, который явно борется и, конечно, не является более чистым способом сделать что-либо.

Как мы можем сделать это более эффективно, избегая всех упомянутых побочных эффектов?

1 Ответ

0 голосов
/ 24 мая 2019

Перемещение легких dom-узлов обычно не очень хорошая идея - ваши пользователи (и браузер) ожидают, что они останутся там, где они есть.

Если вы хотите визуализировать контент где-то еще, вы можете предоставить контент в качестве атрибута.

Упрощенный пример для lit-html (используя его для установки свойства с помощью .)

<my-el .content=${'<div>my content</div>'}></my-el>

Тогда в вашем пользовательском элементе вам нужно будет что-то сделать с этой строкой, которой еще нет в dom.

class MyEl extends ... {
  onContentChanged() {
    document.body.querySelector('my-el-target').innerHTML = this.content;
  }
}

PS: это сильно упрощено - в действительности вы, вероятно, захотите создать / управлять этой my-el-target на connectedCallback - или позволить ей обрабатываться полным контроллером. Кроме того, «шаблон», вероятно, должен быть освещенным шаблоном, а не простой строкой ...

...