Веб-компоненты в ванильном JavaScript

Я создал небольшой веб-компонент без каких-либо фреймворков. Это мой index.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <title></title>
    <meta charset="UTF-8">
    <script src="clock.js" async></script>
</head>

<body>
    <clock-digital></clock-digital>
    <script>
        console.log(document.querySelector('clock-digital').cID);
        document.querySelector('clock-digital').method();
    </script>
</body>

</html>

а это мой clock.js:

customElements.define('clock-digital', class extends HTMLElement {

    get cID() {}

    set cID(value) {}

    constructor() {
        super();
        var shadowRoot = this.attachShadow({
            mode: 'open'
        });
        var that = shadowRoot;
        this.cID = setInterval(function () {
            var currentdate = new Date();
            that.innerHTML = `<div style="display: inline; background-color: whitesmoke; font-style: italic;">${currentdate.getHours()}:${currentdate.getMinutes()}:${currentdate.getSeconds()}</div>`;
        }, 500);
    }

    method() {
        console.log('method');
    }

});

Консоль браузера показывает эту ошибку:

undefined

(index):14 Uncaught TypeError: document.querySelector(...).method is not a function
at (index):14

Почему мой встроенный скрипт не может получить доступ к cID и method()?


person asv    schedule 28.12.2016    source источник
comment
это все еще происходит, если вы назначаете выбор переменной, а затем вызываете методы для этого? Что-то вроде var clock = document.querySelector('clock-digital'); clock.method();   -  person darryn.ten    schedule 28.12.2016
comment
Спасибо, я также должен удалить асинхронность   -  person asv    schedule 28.12.2016


Ответы (2)


Ваш встроенный скрипт запускается до импорта clock.js (что является асинхронным из-за атрибута async, который вы добавили к тегу <script>). Поскольку элемент определен в clock.js, <clock-digital>.method и <clock-digital>.cID еще не существуют, когда ваш встроенный скрипт пытается получить к ним доступ.

Пара вариантов:

  • Удалите тег async, чтобы импорт происходил синхронно перед запуском встроенного скрипта (демонстрация). . Вы потеряете преимущество асинхронной загрузки, но это может не быть проблемой для вас.
  • Запустите встроенный скрипт после тайм-аута (позволив clock.js завершить импорт)
person tony19    schedule 28.12.2016
comment
Это работает, если я удалю асинхронность и напишу var clock = document.querySelector('clock-digital'); часы.метод(); - person asv; 28.12.2016
comment
Тег async — это ваша основная проблема. В демонстрации вы могли видеть, что только удаление async позволяет исходному коду работать как намеревался. Отсутствие кэширования clock не является проблемой. - person tony19; 28.12.2016

Чтобы скрипт оставался асинхронным (async), что иногда лучше, вы можете добавить обработчик события onload к элементу <script>, который будет вызывать ваш встроенный скрипт:

<script>
  function init() {
      console.log(document.querySelector('clock-digital').cID);
      document.querySelector('clock-digital').method();  
  }
</script>

<script src="clock.js" async onload="init()"></script>
person Supersharp    schedule 28.12.2016