#javascript #html #css-grid #shadow-dom #custom-element
#javascript #HTML #css-grid #shadow-dom #пользовательский элемент
Вопрос:
В настоящее время я экспериментирую со слотами в пользовательских элементах.
Посмотрите на этот простой пример:
customElements.define('x-y', class extends HTMLElement {
constructor() {
super();
let template = document.createElement('template');
template.innerHTML = `<style>
:host { display: block; align-self: normal; }
div {
background-color: #666;
color: white;
padding: 5px;
}
</style>
<div>affected by styles from ShadowDOM</div>
<slot name="content"></slot>`;
const shadowRoot = this.attachShadow({
mode: 'open'
}).appendChild(template.content.cloneNode(true));
}
})
body {
border: 2px dashed magenta;
display: grid;
height: 100vh;
grid-template-rows: minmax(0, 1fr);
margin: 0;
}
* {
box-sizing: border-box;
}
x-y>div {
background-color: #f0f0f0;
padding: 5px;
}
.inner-grid {
display: grid;
grid-template-rows: 1fr 2fr;
height: 100%;
overflow: auto;
}
<x-y class="inner-grid">
<div slot="content">not affected by styles from ShadowDOM</div>
</x-y>
Как мы можем видеть, определение сетки для .inner-grid
, хотя и определено в CSS страницы, влияет на отображение содержимого ShadowDOM.
Это, хотя и удобно, стало неожиданным, поскольку внешний CSS не должен влиять на внутренние компоненты веб-компонента (исключениями являются унаследованные свойства и пользовательские свойства).
Второе ожидание, которое у меня было — которое также нарушено, — заключается в том, что контейнер сетки делает так, чтобы его прямые дочерние элементы становились ячейками сетки, к которым применяются определения шаблонов сетки, если таковые имеются. Как элемент внутри ShadowDOM может быть таким прямым дочерним элементом?
Это структура в инспекторе элементов Chrome:
Вопрос: Может ли кто-нибудь пролить некоторый свет на то, как именно это работает? Как CSS grid взаимодействует со смешанным контентом shadow DOM / light DOM? Пожалуйста, добавьте ссылку, если таковая имеется.
Ответ №1:
Я попытался понять ваш вопрос, используя свой собственный код.
Итак, я поместил ваш .inner-grid
элемент в сетку из 3 столбцов <game-board>
Ваш вопрос # 1
Как мы можем видеть, определение сетки для .inner-grid, хотя и определено в CSS страницы, влияет на отображение содержимого ShadowDOM.
Как вы видите, это влияет на содержимое ShadowDOM «?
Красный фон — это то, что вы имеете в виду?
Теневой корень считается элементом, занимающим много места, поэтому равен 1fr
Затем display:grid; grid-template-rows:repeat( 3 , 1fr );
на контейнере увеличится высота контейнера в 3 раза (таким образом, уменьшится его теневой корень).
Ваш вопрос # 2
Второе ожидание, которое у меня было — которое также нарушено, — заключается в том, что контейнер сетки делает так, чтобы его прямые дочерние элементы становились ячейками сетки, к которым применяются определения шаблонов сетки, если таковые имеются. Как элемент внутри ShadowDOM может быть таким прямым дочерним элементом?
Слоты (или фактически разделенное содержимое / «распределенные узлы«) являются прямыми дочерними элементами в сетке
<slot name="A1"></slot> <slot name="A2"></slot> <slot></slot>
<slot name="B1"></slot> <span>gridded in shadowDOM</span> <slot name="B2"></slot>
работа с сеткой 3×2
Примечание:
- В СЛОТЕ A2 ничего нет, он не заполняет область сетки
- 2 элемента из LightDOM переходят в слот по умолчанию
<slot></slot>
и заполняют 2 области сетки.
<template id=GAME-BOARD>
<style description="style shadowDOM">
div {
background: lightgreen;
display: grid; grid-template-columns: repeat(3, 1fr) }
::slotted(*) { border: 3px dashed green }
</style>
<div>
<slot name="A1"></slot> <slot name="A2"></slot> <slot></slot>
<slot name="B1"></slot> <span>gridded in shadowDOM</span> <slot name="B2"></slot>
</div>
</template>
<style description="lightDOM game-pieces">
game-board{ background:red; display:grid; grid-template-rows:repeat(3,1fr)}
game-piece{ background:lightblue }
</style>
<game-board>
<game-piece>to default slot!</game-piece>
<game-piece slot="A1"></game-piece>
<game-piece slot="B2"></game-piece>
<div>GRIDDED from ligthDOM to default slot</div>
</game-board>
<script>
customElements.define('game-board', class extends HTMLElement {
constructor() {
super().attachShadow({mode: 'open'})
.append(document.getElementById(this.nodeName).content.cloneNode(true));
}})
customElements.define('game-piece', class extends HTMLElement {
connectedCallback() {
this.innerHTML = this.getAttribute("slot") || "NO SLOT";
}})
</script>
Если вы хотите создать шахматную доску, вам нужно по умолчанию поместить элемент в каждый из 64 слотов. Они также необходимы для захвата движений перетаскивания / касания.
Тогда проще работать с named grid-template-areas
(в ShadowDOM).
И позиционировать с помощью (64) CSS-селекторов:
::slotted([slot="A5"]){ grid-area:A5 }
И используйте значение по умолчанию <slot></slot>
для захвата фигур, не расположенных на доске.
Я сделал шахматную доску с компонентами 2 года назад: https://chessmeister.github.io (не используя все, что я знаю сейчас)