HTML-разметка внутри компонентов

В Slim.js структура компонентов строится на декларативной HTML-разметке, которая тесно интегрирована с реактивными данными. Основная идея заключается в том, что шаблон компонента определяется внутри функции render() или через строку шаблона, и Slim.js автоматически связывает его с состоянием компонента.

Определение шаблона

В Slim.js компонент создается путем наследования от базового класса Slim. Основная часть — метод render(), возвращающий HTML-структуру. Пример базового компонента:

import Slim from 'slim-js';

class MyComponent extends Slim {
  constructor() {
    super();
    this.title = 'Привет, Slim.js';
  }

  render() {
    return `
      <div class="container">
        <h1>${this.title}</h1>
      </div>
    `;
  }
}

customElements.define('my-component', MyComponent);

Ключевой момент: шаблон компонента — это строка, где можно использовать интерполяцию значений через ${}, связывая DOM с состоянием объекта.

Динамическое обновление содержимого

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

class CounterComponent extends Slim {
  constructor() {
    super();
    this.count = 0;
  }

  increment() {
    this.count++;
  }

  render() {
    return `
      <div>
        <p>Счетчик: ${this.count}</p>
        <button oncl ick="${() => this.increment()}">Увеличить</button>
      </div>
    `;
  }
}

customElements.define('counter-component', CounterComponent);

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

  • Любое изменение свойства count автоматически обновит содержимое <p>.
  • Обработчики событий можно назначать прямо через строку шаблона с использованием функций компонента.

Встраивание вложенных компонентов

Slim.js поддерживает вложенные компоненты. Их можно использовать как обычные HTML-теги:

class ChildComponent extends Slim {
  render() {
    return `<span>Вложенный компонент</span>`;
  }
}

customElements.define('child-component', ChildComponent);

class ParentComponent extends Slim {
  render() {
    return `
      <div>
        <h2>Родительский компонент</h2>
        <child-component></child-component>
      </div>
    `;
  }
}

customElements.define('parent-component', ParentComponent);

Важно: Slim.js автоматически рендерит дочерний компонент и поддерживает его реактивность, если свойства изменяются.

Условный рендеринг

Для управления отображением элементов внутри шаблона используются тернарные операторы и логические выражения:

class ToggleComponent extends Slim {
  constructor() {
    super();
    this.showText = true;
  }

  toggle() {
    this.showText = !this.showText;
  }

  render() {
    return `
      <div>
        ${this.showText ? '<p>Текст видим</p>' : ''}
        <button oncl ick="${() => this.toggle()}">Переключить</button>
      </div>
    `;
  }
}

customElements.define('toggle-component', ToggleComponent);

Принцип: любые изменения состояния автоматически приводят к обновлению DOM без необходимости удаления или вставки элементов вручную.

Циклический рендеринг

Slim.js позволяет создавать списки элементов с помощью методов массива внутри шаблона:

class ListComponent extends Slim {
  constructor() {
    super();
    this.items = ['Яблоко', 'Банан', 'Вишня'];
  }

  render() {
    return `
      <ul>
        ${this.items.map(item => `<li>${item}</li>`).join('')}
      </ul>
    `;
  }
}

customElements.define('list-component', ListComponent);

Замечание: метод map() генерирует строку HTML для каждого элемента массива. При изменении this.items Slim.js перерисует список полностью или частично, в зависимости от изменений.

Работа с атрибутами и классами

HTML-разметка в Slim.js поддерживает динамическое изменение атрибутов и классов через выражения Jav * aScript:

class StyledComponent extends Slim {
  constructor() {
    super();
    this.isActive = false;
  }

  toggleActive() {
    this.isActive = !this.isActive;
  }

  render() {
    return `
      <div class="${this.isActive ? 'active' : 'inactive'}">
        <p>Состояние: ${this.isActive ? 'Активно' : 'Неактивно'}</p>
        <button oncl ick="${() => this.toggleActive()}">Переключить</button>
      </div>
    `;
  }
}

customElements.define('styled-component', StyledComponent);

Ключевой момент: использование тернарных операторов для классов и атрибутов позволяет динамически изменять стили и поведение компонентов без обращения к classList или setAttribute.

Поддержка событий

События в Slim.js можно привязывать через шаблон или метод addEventListener. Прямое указание функции через ${() => ...} гарантирует, что контекст this останется привязанным к компоненту:

<button oncl ick="${() => this.handleClick()}">Клик</button>

Для сложных обработчиков или делегирования можно использовать обычный addEventListener внутри метода onBeforeMount:

onBeforeMount() {
  this.querySelector('button').addEventListener('click', () => this.handleClick());
}

Итоговая структура компонента

С учетом всех возможностей Slim.js компонент состоит из:

  1. Свойств состояния, определяющих динамические данные.
  2. Методов, изменяющих состояние и вызывающих обновление.
  3. Метода render(), где описывается HTML-разметка с привязкой к данным.
  4. Встроенных обработчиков событий, позволяющих управлять реактивным поведением.

Использование этих элементов позволяет создавать сложные, модульные и реактивные интерфейсы с минимальной зависимостью от ручного DOM-манипулирования.