Как создать веб-компонент для Reveal.js

Как создать веб-компонент для Reveal.js

11 мая 2023 г.

Я являюсь поклонником Reveal.js много лет. Reveal.js – это веб-фреймворк для презентаций, который (в основном) упрощает создание слайдов с помощью простого HTML.

Я совсем не против Powerpoint, и он невероятно мощный, но когда я выступаю на веб-темы (что обычно происходит в 99% случаев), мне не нравится опыт «альт-таббинга» из работающий Powerpoint для кода или вкладок браузера.

Reveal.js помогает мне этого избежать.

Использовать Reveal (я уже устал печатать многоточие) относительно просто. Вы добавляете тег скрипта. Вы добавляете два тега ссылки для CSS (один для основного CSS и один для темы), а затем начинаете писать HTML. Тег section используется для каждого слайда. Вот пример того, насколько это просто, из их документации:

<html>
  <head>
    <link rel="stylesheet" href="dist/reveal.css">
    <link rel="stylesheet" href="dist/theme/white.css">
  </head>
  <body>
    <div class="reveal">
      <div class="slides">
        <section>Slide 1</section>
        <section>Slide 2</section>
      </div>
    </div>
    <script src="dist/reveal.js"></script>
    <script>
      Reveal.initialize();
    </script>
  </body>
</html>

В приведенном выше фрагменте вы можете увидеть два тега section, представляющие каждый слайд. Там довольно много, и если вы хотите увидеть больше, посмотрите их демонстрацию, но на сегодня мне было любопытно, если я может упростить создание презентаций Reveal с помощью веб-компонентов. Вот что у меня получилось.

Версия первая

Сначала я поделюсь HTML-кодом, который хотел использовать. На самом деле я сначала написал это, а затем начал создавать веб-компонент, чтобы увидеть, как он сам обновляется.

<reveal-preso theme="beige">
    <section>Slide 1b</section>
    <section>Slide 2</section>
    <section>Slide 3</section>
    <section data-background-color="aquamarine">
        <h2>🍦</h2>
    </section>
    <section data-background-image="https://placekitten.com/800/800">
        <h2>Image</h2>
    </section>  
</reveal-preso>

Мой HTML использует веб-компонент reveal-preso и поддерживает атрибут theme. Внутри компонента находится набор тегов section для слайдов. (К вашему сведению, я мог бы также создать дочерний тег reveal-slide, и я сделаю это в своем следующем посте!) У меня нет сценария или теги ссылок вообще.

Теперь давайте посмотрим на определение компонента.

class RevealPreso extends HTMLElement {
    constructor() {
        super();
    }

    connectedCallback() {

        this.theme = 'black';
        if(this.hasAttribute('theme')) {
            this.theme = this.getAttribute('theme');
        }

        let currentHTML = this.innerHTML;
        this.innerHTML = `
<div class="reveal">
    <div class="slides">
        ${currentHTML}
    </div>
</div>
        `;

        // load reveal.js
        const script = document.createElement('script');
        script.type = 'text/javascript';
        script.async = true;
        script.src = 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/4.5.0/reveal.js';
        document.head.appendChild(script);

        const link = document.createElement('link');
        link.rel = 'stylesheet';
        link.type='text/css';
        link.href = 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/4.5.0/reveal.min.css';
        document.head.appendChild(link);

        const theme = document.createElement('link');
        theme.rel = 'stylesheet';
        theme.type='text/css';
        theme.href = `https://cdnjs.cloudflare.com/ajax/libs/reveal.js/4.5.0/theme/${this.theme}.min.css`;
        document.head.appendChild(theme);

        script.addEventListener('load', () => {
            Reveal.initialize();
        });

    }
}

if(!customElements.get('reveal-preso')) customElements.define('reveal-preso', RevealPreso);

Как видите, это относительно просто. Мой connectedCallback переписывает внутренний HTML таким образом, что он заключен в divs, которые ожидает Reveal. Затем я динамически загружаю все три ресурса — мой JavaScript и оба ресурса CSS.

У меня есть прослушиватель событий в скрипте, так что после его загрузки я могу инициализировать презентацию.

Из того, что я мог видеть (через Google и Stack Overflow), нет onload для скриптов CSS. Я видел несколько предложенных обходных путей, но решил не усложнять ситуацию и побеспокоиться только о ресурсе JavaScript. Я понимаю, что это может быть проблематично.

Еще одна проблема - мой код проверяет аргумент темы только один раз. Если бы вы позже изменили его с помощью JavaScript, он бы этого не заметил.

(Если бы я был настолько смел, чтобы предложить здесь передовую практику, я, вероятно, предложил бы вам всегда иметь код для распознавания изменений атрибутов или четкого документирования того, что не будет работать.) Вот как это выглядит. :

https://codepen.io/cfjedimaster/pen/MWPJgMJ?embedable=true

Лично я считаю, что это очень круто! Но обратите внимание, что он ожидает всего веб-представления. Это значение по умолчанию для Reveal, и, вероятно, так его использует большинство людей, но я действительно хотел посмотреть, можно ли встроить Reveal вместе с другим веб-контентом. Вот как я это сделал.

Версия вторая

Сначала я проверил документы. Я когда-либо использовал Reveal только как полноценную веб-презентацию, и я не знал, поддерживает ли это сам фреймворк. Оказывается, у него есть встроенный режим. Также поддерживается несколько встроенных презентаций.

Для этого требуются две вещи: небольшое изменение в том, как вы инициализируете объект Reveal, и предоставление определенных размеров контейнера, содержащего вашу презентацию.

Я начал с того, что немного изменил свой HTML:

<h2>Preso</h2>

<p>
    Here is my preso. It brings all the boys to the yard.
</p>

<reveal-preso height="700px" theme="dracula">
    <section>Slide 1b</section>
    <section>
        <h2>Plan</h2>
        <ul>
            <li class="fragment">Phase One - Collect Underpants</li>
            <li class="fragment">Phase Two - ?</li>
            <li class="fragment">Phase Three - Profit</li>
        </ul>
    </section>
    <section>Slide 3</section>
    <section data-background-color="aquamarine">
        <h2>🍦</h2>
    </section>
    <section data-background-image="https://placekitten.com/800/800">
        <h2>Image</h2>
    </section>  
</reveal-preso>

<footer>
End of page.
</footer>

У меня есть какая-то базовая хрень сверху и снизу, а в теге reveal-preso я добавил height. Мой компонент будет поддерживать как height, так и width, но по умолчанию он будет использовать оба. Теперь давайте посмотрим на обновленный компонент:

class RevealPreso extends HTMLElement {
    constructor() {
        super();
    }

    connectedCallback() {
        console.log('connected callback called');

        // defaults
        this.width = '100%';
        this.height = '500px';
        this.theme = 'black';
        if(this.hasAttribute('width')) {
            this.width = this.getAttribute('width');
        }
        if(this.hasAttribute('height')) {
            this.height = this.getAttribute('height');
        }
        if(this.hasAttribute('theme')) {
            this.theme = this.getAttribute('theme');
        }

        let currentHTML = this.innerHTML;
        this.innerHTML = `
<div class="reveal" style="width: ${this.width}; height: ${this.height}">
    <div class="slides">
        ${currentHTML}
    </div>
</div>
        `;

        // load reveal.js
        const script = document.createElement('script');
    script.type = 'text/javascript';
    script.async = true;
        script.src = 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/4.5.0/reveal.js';
        document.head.appendChild(script);

        const link = document.createElement('link');
        link.rel = 'stylesheet';
        link.type='text/css';
        link.href = 'https://cdnjs.cloudflare.com/ajax/libs/reveal.js/4.5.0/reveal.min.css';
        document.head.appendChild(link);

        const theme = document.createElement('link');
        theme.rel = 'stylesheet';
        theme.type='text/css';
        theme.href = `https://cdnjs.cloudflare.com/ajax/libs/reveal.js/4.5.0/theme/${this.theme}.min.css`;
        document.head.appendChild(theme);

        script.addEventListener('load', () => {
         Reveal(this.querySelector( '.reveal' ), {
                embedded: true,
                keyboardCondition: 'focused' // only react to keys when focused
         }).initialize();

        });

    }
}

if(!customElements.get('reveal-preso')) customElements.define('reveal-preso', RevealPreso);

Я обновил код, чтобы теперь искать height и width и по умолчанию оба. Когда я переписываю внутреннее содержимое HTML, я включаю эти значения. Наконец, я изменил способ инициализации презентации. Вы можете увидеть это в действии здесь:

https://codepen.io/cfjedimaster/pen/GRYrRmK?embedable=true

Есть еще вещи, которые я бы подправил здесь. Я бы определенно добавил поддержку изменения высоты и ширины. Сам Reveal также поддерживает распознавание изменений своего размера.

Одно примечание: я провел быстрый тест с двумя презентациями на странице, и он сработал, но он показывает только одну тему, и я считаю, что нет обходного пути, поскольку Reveal ожидает только одну тему CSS.

Возможно, но я не уверен.

Следующая версия?

Как я уже говорил ранее, я хочу повторить это еще раз. Я хочу создать дочерний тег reveal-slide (или, возможно, что-то короче) и изучить возможность импорта тега из другого ресурса JavaScript.

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


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE