Постепенное внедрение Slim.js

Slim.js — это лёгкая библиотека для создания веб-компонентов с минимальным объёмом кода и высокой производительностью. Она опирается на нативные возможности браузера, такие как Custom Elements и Shadow DOM, и предоставляет простой синтаксис для объявления компонентов, их состояния и реактивного обновления DOM.

Компонент в Slim.js — это класс, расширяющий Slim, с декларативным описанием разметки и методов жизненного цикла:

class MyComponent extends Slim {
  get useShadow() { return true; }

  get template() {
    return `
      <div>
        <p>{message}</p>
        <button click="updateMessage">Обновить</button>
      </div>
    `;
  }

  message = "Привет, Slim!";

  updateMessage() {
    this.message = "Сообщение обновлено!";
  }
}

Slim.tag('my-component', MyComponent);

Ключевые моменты:

  • useShadow определяет, будет ли компонент использовать Shadow DOM.
  • template возвращает HTML-разметку компонента с возможностью связывать данные через фигурные скобки {}.
  • Любое свойство, объявленное в классе, становится реактивным. При изменении свойства Slim автоматически обновляет DOM.

Декларативное связывание данных

Slim.js использует реактивность на уровне свойств компонента. Любое изменение данных отражается в DOM без необходимости вручную манипулировать элементами:

class Counter extends Slim {
  count = 0;

  get template() {
    return `
      <div>
        <span>Счётчик: {count}</span>
        <button click="increment">+</button>
        <button click="decrement">-</button>
      </div>
    `;
  }

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

Slim.tag('my-counter', Counter);

Особенности:

  • Любая привязка данных в фигурных скобках {} автоматически отслеживает изменения.
  • Методы компонента могут быть привязаны к событиям через атрибуты, например, click="increment".
  • Реактивность распространяется и на вложенные компоненты.

Управление жизненным циклом компонентов

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

  • onBeforeCreated() — вызывается перед инициализацией компонента.
  • onCreated() — выполняется сразу после создания экземпляра.
  • onBeforeRender() — вызывается перед рендером DOM.
  • onRendered() — после того как DOM вставлен в страницу.
  • onAttributeChanged(attr, oldVal, newVal) — при изменении атрибута компонента.

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

class LifecycleDemo extends Slim {
  message = "Старт";

  get template() { return `<p>{message}</p>`; }

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

  onRendered() {
    console.log("Компонент вставлен в DOM");
  }
}

Slim.tag('lifecycle-demo', LifecycleDemo);

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


Взаимодействие с атрибутами

Slim.js позволяет легко связывать свойства компонента с HTML-атрибутами. При этом обновления атрибутов отражаются на свойствах и наоборот:

class UserCard extends Slim {
  name = "Неизвестный";

  get template() {
    return `<div>Пользователь: {name}</div>`;
  }
}

Slim.tag('user-card', UserCard);

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

<user-card name="Алексей"></user-card>

Механизм работы:

  • Атрибут name автоматически инициализирует свойство name компонента.
  • Изменение свойства name через JavaScript обновляет DOM без ручного вмешательства.

Вложенные компоненты и слоты

Slim.js поддерживает вложенные компоненты и использование slot для передачи контента внутрь компонента:

class Card extends Slim {
  get useShadow() { return true; }

  get template() {
    return `
      <div class="card">
        <slot></slot>
      </div>
    `;
  }
}

Slim.tag('app-card', Card);

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

<app-card>
  <p>Внутреннее содержимое карточки</p>
</app-card>

Особенности:

  • Слоты позволяют создавать гибкие компоненты с динамическим содержимым.
  • Shadow DOM изолирует стили компонента, предотвращая конфликт с внешними CSS.

Реактивные списки и циклы

Slim.js поддерживает динамическое создание списков через директиву {for item in items}:

class TodoList extends Slim {
  items = ["Купить хлеб", "Прочитать книгу", "Сделать задачу"];

  get template() {
    return `
      <ul>
        {for task in items}
          <li>{task}</li>
        {/for}
      </ul>
    `;
  }
}

Slim.tag('todo-list', TodoList);

Особенности:

  • {for ...} автоматически отслеживает изменения массива.
  • Добавление или удаление элементов через методы массива обновляет DOM без ручного рендеринга.

События и взаимодействие между компонентами

Slim.js позволяет создавать кастомные события и передавать данные между компонентами:

class ButtonEmit extends Slim {
  get template() {
    return `<button click="sendEvent">Нажми</button>`;
  }

  sendEvent() {
    this.dispatchEvent(new CustomEvent('my-event', { detail: { value: 42 } }));
  }
}

Slim.tag('button-emit', ButtonEmit);

Подписка на событие:

<button-emit onmy-event="handleEvent"></button-emit>
<script>
  function handleEvent(e) {
    console.log("Получено значение:", e.detail.value);
  }
</script>

Особенности:

  • События можно слушать через стандартные HTML-атрибуты on*.
  • CustomEvent позволяет передавать любые данные между компонентами.

Подключение стилей

Slim.js поддерживает использование стилей внутри компонентов:

class StyledComponent extends Slim {
  get useShadow() { return true; }

  get template() {
    return `
      <style>
        p { color: blue; font-weight: bold; }
      </style>
      <p>Стилизованный текст</p>
    `;
  }
}

Slim.tag('styled-component', StyledComponent);

Особенности:

  • Стили изолированы при использовании Shadow DOM.
  • Можно комбинировать внутренние и внешние CSS для комплексного оформления.

Интеграция с существующими приложениями

Slim.js легко внедряется в существующие проекты:

  • Компоненты создаются как самостоятельные модули.
  • Легко смешиваются с vanilla JS, jQuery или другими фреймворками.
  • Можно постепенно заменять отдельные элементы на Slim-компоненты, что упрощает миграцию.

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