Есть ли способ получить доступ к атрибуту HTML-тега в CSS в Shadow-DOM?

#html #css #typescript #shadow-dom #stenciljs

#HTML #css #typescript #shadow-dom #stenciljs

Вопрос:

Я создаю пользовательский компонент с помощью StencilJS, и мне нужно внести некоторые изменения в контур, когда пользователь использует клавиатуру или мышь для перехода к компоненту.

Мой компонент использует ShadowDOM, и я хочу получить доступ к атрибуту HTML-тега из CSS.

Атрибуты тега генерируются с помощью what-input (https://github.com/ten1seven/what-input ) для обнаружения событий клавиатуры и мыши.

Я пробовал использовать CSS-селекторы, такие как [data-whatintent=keyboard] и html[data-whatintent=keyboard] , но это не сработало.

Это мой HTML-тег, из которого я хочу получить доступ к data-whatintent атрибуту:

 <html dir="ltr" lang="en" data-whatinput="keyboard" data-whatintent="mouse">

  <my-custom-component></my-custom-component>

</html>

  

И это мой CSS:

 [data-whatintent=keyboard] *:focus {
  outline: solid 2px #1A79C6;
}
  

Я хочу, чтобы мой CSS в ShadowDOM мог использовать значение data-whatintent атрибута для установки стилей в моем компоненте, чтобы контур был таким, как я хочу.

Комментарии:

1. Вы можете легко получить к нему доступ из компонента, например, document.querySelector('html').getAttribute('data-whatintent') , но применение значения атрибута к стилю — это совсем другой вопрос. Что именно вам нужно сделать со значением? Существует ли конечное число возможных значений, которые вы знаете заранее?

2. Только 2 возможных значения: клавиатура или мышь, но я хочу, чтобы CSS действовал только тогда, когда значение равно keyboard .

Ответ №1:

Ответ Supersharp правильный, однако это не код StencilJS, а также поддержка контекста хоста ненадежна (не работает в Firefox и, вероятно, IE11).

Вы можете «перенести» атрибут в элемент host, а затем использовать селектор из стиля компонента host:

TSX:

 private intent: String;

componentWillLoad() {
    this.intent = document.querySelector('html').getAttribute('data-whatintent');
}

hostData() {
    return {
        'data-whatintent': this.intent
    };
}
  

SCSS:

 :host([data-whatintent="keyboard"]) *:focus {
    outline: solid 2px #1A79C6;
}
  

Если data-whatintent атрибут изменяется динамически, сделайте его свойством компонента и попросите функцию прослушивания обновить ваш компонент. При желании вы можете использовать свойство для добавления / удаления классов на хост для стилизации, хотя вы также могли бы продолжать использовать селектор атрибутов.

TSX:

 @Prop({ mutable: true, reflectToAtrr: true }) dataWhatintent: String;

componentWillLoad() {
    this.dataWhatintent = document.querySelector('html').getAttribute('data-whatintent');
}

hostData() {
    return {
        class: { 
            'data-intent-keyboard': this.dataWhatintent === 'keyboard' 
        }
    };
}
  

SCSS:

 :host(.data-intent-keyboard) *:focus {
    outline: solid 2px #1A79C6;
}
  

Обработчик событий клавиатуры и мыши документа:

 function intentHandler(event: Event) {
    const intent = event instanceof KeyboardEvent ? 'keyboard' : 'mouse';
    document.querySelectorAll('my-custom-component').forEach(
        el => el.setAttribute('data-whatintent', intent)
    );
}
  

Комментарии:

1. При этом intent всегда будет иметь одно и то же значение? Значение data-whatintent обновляется каждый раз, когда пользователь перемещает мышь или нажимает клавишу.

2. Если это вариант использования, то любой прослушиватель, обрабатывающий использование мыши и клавиатуры, должен запустить событие, которое компонент может прослушать и обновить значение «intent». В любом случае, один из возможных подходов.

3. Мой CSS не обновлялся, но мой компонент повторно визуализируется и intent обновляется правильно…

4. Я добавил пример для динамического обновления.

Ответ №2:

Вы могли бы использовать:host-context() для применения стиля CSS в Shadow DOM в зависимости от контекста, в котором используется пользовательский элемент.

 customElements.define( 'my-custom-component', class extends HTMLElement {
    constructor() {
        super()
        this.attachShadow( { mode: 'open' } )
            .innerHTML = `
              <style>
                :host-context( [data-whatinput=keyboard] ) *:focus {
                   outline: solid 2px #1A79C6;
                }
              </style>
              <input value="Hello">`
    }
} )         
             
 <html dir="ltr" lang="en" data-whatinput="keyboard" data-whatintent="mouse">

  <my-custom-component></my-custom-component>

</html>  

Комментарии:

1. Это не сработало с использованием Stencil. У меня не было доступа к attachShadow() .

2. @vincino но вы можете определить CSS для своего компонента no?