Как получить доступ к элементу глубоко внутри shadow-root

#javascript #html #css #vaadin #lit-element

#javascript #HTML #css #vaadin #lit-элемент

Вопрос:

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

 <vaadin-combo-box>
        #shadow-root
            <vaadin-text-field id="input">
                <vaadin-combo-box-dropdown-wrapper id="overlay">
                    #shadow-root(open)
                        <vaadin-combo-box-dropdown id="dropdown">
                            #shadow-root(open)
                                <vaadin-combo-box-overlay id="overlay">
                                    #shadow-root(open)
                                     <div part="overlay" id="overlay">
                                        <div part="content" id="conent">
                                            #shadow-root(open)
                                                <div id="scroller">
                                                    <iron-list id="selector">
                                                        #shadow-root(open)
                                                            <vaadin-combo-box-item>
                                                                ......
                                                               
  

Я хочу создать элемент vaadin-combo-box-item, но я не знаю, как получить доступ к этому элементу.

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

1. Я вижу там некоторые атрибуты части… можете ли вы попросить Vaadin экспортировать эти части CSS, чтобы вы могли стилизовать их, не проникая в корни shadow?

2. Для того, чтобы стилизовать vaadin-combo-box-item, вы также можете рассмотреть возможность использования ComponentRenderer (см. vaadin.com/components/vaadin-combo-box/java-examples /… ).

Ответ №1:

На это нет простого ответа, потому что вам нужно получить доступ к очень глубокому элементу DOM.

Чтобы сделать это немного менее болезненным, вам нужно создать функцию, доступ к которой обеспечивал shadow dom элемента, например:

 const getShadowRoot = (elem, selector) => elem.shadowRoot.querySelector(selector);

const vaadinComboBox = getShadowRoot(document, 'vaadin-combo-box');
const vaadinTextField = getShadowRoot(vaadinComboBox, '#input');
const vaadinComboBoxWrapper = getShadowRoot(vaadinTextField, '#overlay');
const vaadinComboBoxDropdown = getShadowRoot(vaadinComboBoxWrapper, '#dropdown');
const vaadinComboBoxOverlay = getShadowRoot(vaadinComboBoxDropdown, '#overlay');
const vaadinComboBoxContent = getShadowRoot(vaadinComboBoxOverlay, '#conent');
const vaadinComboBoxSelector = getShadowRoot(vaadinComboBoxContent, '#selector');
const vaadinComboBoxItem = getShadowRoot(vaadinComboBoxContent, 'vaadin-combo-box-item');
  

Тем не менее, такое количество элементов ShadowDOM выглядит как архитектурная ошибка

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

1. вы уверены, что это правильно? потому что, когда я использую vaadinComboBoxItem.style.background = "green" , ничего не происходит

2. я думаю, что это будет elem.shadowRoot. querySelector(селектор)

3. Функция getShadowRoot возвращает shadowRoot атрибут каждый раз, поэтому вам не нужно обращаться к нему каждый раз. Может быть, parent of <vaadin-combo-box> — это не body, а также shadow root?

4. ваш родительский элемент <vaadin-combo-box> также является теневым корнем

5. <vaadin-dialog-overlay> #shadow-root ......... <vaadin-combo-box> ........

Ответ №2:

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

 function* descend(el, sel, parent) {
        if (el.matches(sel)) {
            yield parent ? el.parentElement : el;
        }
        if (el.shadowRoot) {
            for (const child of el.shadowRoot.children) {
                yield* descend(child, sel, parent);
            }
        }
        for (const child of el.children) {
            yield* descend(child, sel, parent);
        }
    };
  

Пример использования:

 const vid = [...descend(window.parent.document.querySelector("body"), "video", false)][0]