Custom Elements

Slim.js — это легковесная библиотека для создания компонентного интерфейса в JavaScript, основанная на концепции Web Components. Она позволяет создавать кастомные элементы, которые инкапсулируют логику, разметку и стили, обеспечивая повторное использование кода и чистую архитектуру.

Определение пользовательского элемента

Пользовательский элемент в Slim.js создается с помощью функции Slim.tag. Эта функция принимает три аргумента:

  1. Имя тега — строка, соответствующая стандарту кастомных элементов, с дефисом (my-component).
  2. Класс или объект с методами и свойствами — определяет поведение компонента.
  3. Опциональная конфигурация — настройки связывания данных, шаблона и слотов.

Пример базового элемента:

Slim.tag('my-button', class extends Slim {
    get template() {
        return `<button>{{label}}</button>`;
    }

    constructor() {
        super();
        this.label = 'Нажми меня';
    }

    click() {
        console.log('Кнопка нажата');
    }
});

В этом примере:

  • template — строка с HTML-разметкой, где {{label}} автоматически связывается с свойством label.
  • Метод click можно вызывать из шаблона через слушатели событий.

Связывание данных

Slim.js использует одностороннее связывание данных по умолчанию. Любое изменение свойства компонента автоматически обновляет DOM. Связь задается через {{propertyName}} в шаблоне.

Пример динамического обновления:

Slim.tag('counter-element', class extends Slim {
    get template() {
        return `
            <div>
                <p>Счётчик: {{count}}</p>
                <button oncl ick="increment()">Увеличить</button>
            </div>
        `;
    }

    constructor() {
        super();
        this.count = 0;
    }

    increment() {
        this.count += 1;
    }
});

Каждое изменение this.count мгновенно отражается в DOM.

Атрибуты и наблюдение за ними

Кастомные элементы в Slim.js поддерживают связывание атрибутов с свойствами. Атрибуты объявляются через статическое свойство observedAttributes. Любое изменение атрибута автоматически обновляет соответствующее свойство.

Пример:

Slim.tag('color-box', class extends Slim {
    static get observedAttributes() { return ['color']; }

    get template() {
        return `<div style="width:100px; height:100px; background-color:{{color}}"></div>`;
    }

    constructor() {
        super();
        this.color = 'red';
    }
});

Использование:

<color-box color="blue"></color-box>

Изменение атрибута через Jav * aScript:

document.querySelector('color-box').setAttribute('color', 'green');

обновит цвет элемента мгновенно.

События внутри компонентов

Slim.js позволяет генерировать кастомные события и подписываться на них. Для генерации события используется метод dispatchEvent.

Пример:

Slim.tag('notify-button', class extends Slim {
    get template() {
        return `<button oncl ick="notify()">Уведомить</button>`;
    }

    notify() {
        this.dispatchEvent(new CustomEvent('notify', {
            detail: { message: 'Событие произошло!' },
            bubbles: true
        }));
    }
});

Подписка:

document.querySelector('notify-button').addEventListener('notify', (e) => {
    console.log(e.detail.message);
});

Слоты и композиция компонентов

Slim.js поддерживает слоты для вставки внешнего контента в шаблон компонента. Используются стандартные <slot>:

Slim.tag('card-element', class extends Slim {
    get template() {
        return `
            <div class="card">
                <h3>{{title}}</h3>
                <slot></slot>
            </div>
        `;
    }

    constructor() {
        super();
        this.title = 'Заголовок карточки';
    }
});

Использование:

<card-element title="Карточка 1">
    <p>Содержимое карточки вставлено через слот</p>
</card-element>

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

Жизненный цикл компонента

Slim.js поддерживает основные методы жизненного цикла Web Components:

  • onBeforeCreated() — вызывается перед инициализацией свойства template.
  • onCreated() — после создания компонента и привязки данных.
  • onBeforeUpdate() — перед обновлением DOM при изменении свойств.
  • onUpdated() — после обновления DOM.
  • onRemoved() — при удалении элемента из DOM.

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

Slim.tag('lifecycle-element', class extends Slim {
    get template() { return `<p>{{message}}</p>`; }

    constructor() {
        super();
        this.message = 'Инициализация';
    }

    onCreated() {
        console.log('Компонент создан');
    }

    onUpdated() {
        console.log('Компонент обновлён');
    }

    onRemoved() {
        console.log('Компонент удалён');
    }
});

Динамическая загрузка компонентов

Slim.js позволяет создавать и регистрировать компоненты динамически, что полезно для ленивой загрузки больших приложений. Динамический тег регистрируется через тот же Slim.tag, при этом можно подключать шаблон и стили из внешних ресурсов.

Пример:

import('components/dynamic-component.js').then(() => {
    console.log('Компонент загружен и готов к использованию');
});

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

Стиль и инкапсуляция

Slim.js позволяет применять локальные стили через style внутри шаблона, что обеспечивает инкапсуляцию CSS:

Slim.tag('styled-box', class extends Slim {
    get template() {
        return `
            <style>
                div { width:100px; height:100px; background-color:{{color}}; border-radius:8px; }
            </style>
            <div></div>
        `;
    }

    constructor() {
        super();
        this.color = 'orange';
    }
});

Стили применяются только к внутреннему DOM компонента, не влияя на внешний контент страницы.


Этот набор возможностей Slim.js делает его удобным инструментом для построения компонентной архитектуры, где каждый пользовательский элемент может иметь собственный шаблон, логику, стили и события, сохраняя при этом чистоту и модульность кода.