невозможно получить доступ к стилям с помощью getComputedStyle в connectedCallback веб-компонента

Я новичок в javascript и играл с веб-компонентами. Я хотел получить доступ к атрибуту цвета CSS элемента внутри теневой DOM веб-компонента. Когда я использую метод getComputedStyle (), я не могу получить доступ к свойству стиля при его запуске в connectedCallback.

Здесь я пытаюсь получить доступ к свойству цвета, при регистрации значения на консоли он показывает RGB (0, 0, 0), тогда как после ожидания миллисекунды и затем регистрации отображается правильное значение RGB (0, 128, 0). вверх. Почему это происходит?

Я полагаю, это потому, что стили еще не были вычислены, когда я впервые запускаю функцию? Какое решение может быть более элегантным? Как я могу дождаться, пока будут вычислены стили для запуска моей функции, вместо некоторого произвольного времени, которое я указываю сейчас?

JS

document.addEventListener('DOMContentLoaded',()=>{

    class CustomComponent extends HTMLElement{
        constructor(){
            super();

            this.attachShadow({mode:'open'});

            const template=document.querySelector('#component');
            this.shadowRoot.appendChild(template.content.cloneNode(true));
        };

        connectedCallback(){
            console.log('Element added to DOM');

            let text=this.shadowRoot.querySelector('.text');
            console.log(getComputedStyle(text).getPropertyValue('color'));
            setTimeout(()=>{console.log(getComputedStyle(text).getPropertyValue('color'))},1)
        };
    };

    customElements.define('custom-component',CustomComponent);
});

CSS

.container{
    --color-variable:#f2c846;
}

.text{
    color:green;
}
  

HTML

<!DOCTYPE html>
<html lang="en" dir="ltr">
    <head>
        <meta charset="utf-8">
        <title>Random title</title>
        <script src='./CustomComponent.js'></script>
    </head>
    <body>
        <template id='component'>
            <link rel='stylesheet' href='./CustomComponent.css'/>
            <div class=container>
                <div class='text'>
                    Colored Text
                </div>
            </div>
        </template>
        <custom-component>

        </custom-component>
    </body>
</html>

person Merlin11    schedule 23.07.2020    source источник


Ответы (1)


Уф, расстраивает. Я думаю, ваша интуиция, вероятно, права насчет того, что стили не готовы сразу, и ваш инстинкт ожидания - это то, с чем я тоже могу согласиться.

Я не думаю, что это совершенно необычно видеть setTimeout(callback) - второй аргумент в этом случае излишен - как сигнал о том, что вы ждете, пока цикл событий запустится один раз (что позволяет стилям вычисляться). requestAnimationFrame(callback) может иметь дополнительное преимущество в виде сигнала о том, что вы тоже ждете некоторой визуальной готовности, хотя для этой цели он не превзойдет setTimeout. Я буду первым, кто скажет, что я не нахожу эти решения такими же удовлетворительными, как встроенный обратный вызов или событие, которое нужно прослушивать, и я бы предположил, что connectedCallback было именно этим.

Кроме того, если вы не возражаете против использования фреймворка (например, Stencil), который упрощает работу с веб-компонентами, будет обратные вызовы, предоставляемые фреймворком, которые сообщают вам, когда компонент был полностью отрисован.

person Impirator    schedule 23.07.2020
comment
Спасибо, приятель. И да, в конечном итоге я планировал использовать какой-то фреймворк, я просто хотел почувствовать вкус вещей, просто используя обычные веб-компоненты. - person Merlin11; 23.07.2020
comment
Забавно, вы хотите загрузить дополнительный код Framework, чтобы избежать использования техники, которая задерживает выполнение кода с connectedCallback до тех пор, пока Eventloop не будет очищен; ту же технику, которую Frameworks используют под капотом. connectedCallback может получить доступ к DOM в FireFox, но не может (и правильно) в браузерах на основе Webkit: stackoverflow.com/questions/61971919/ - person Danny '365CSI' Engelman; 24.07.2020
comment
Примечание: setTimeout(()=>{ code }); - вполне допустимый код, и этого достаточно. Не требуется 0. Как и RAF (requestAnimationFrame), он ждет, пока Eventloop не станет пустым (и, следовательно, ваша DOM существует). Я еще не видел проекта, где RAF лучше, чем setTimeout. Если вы действительно используете очень тяжелую анимацию, см .: stackoverflow.com/questions/38709923/) - person Danny '365CSI' Engelman; 24.07.2020
comment
@ Danny'365CSI'Engelman, справедливо замечание о дополнительном коде фреймворка, который делает то же самое. Это определенно субъективное мнение, что со структурой фреймворка работать лучше. Этот лишний второй аргумент для setTimeout является личным пережитком кодовой базы, которая ожидала явной передачи параметров в качестве меры предосторожности и в качестве примечания о намерениях для других разработчиков. Однако мне не следует обременять других своим обусловленным поведением, поэтому я внесу правку. :) - person Impirator; 24.07.2020
comment
Я осаждаю других своим мнением .. Так что ничего не редактируйте. Библиотеки - это инструменты, используйте их, если понимаете, что делает этот инструмент. Увы, большинство пользователей инструментов понятия не имеют о лежащей в основе технологии. Так же поступало большинство из нас во времена jQuery ... - person Danny '365CSI' Engelman; 24.07.2020