Организация кода

SkateJS — это легковесная библиотека для создания веб-компонентов, построенная поверх стандартов Custom Elements и Shadow DOM. Она позволяет структурировать код, обеспечивая модульность, переиспользуемость и инкапсуляцию. В SkateJS компоненты описываются через объект конфигурации, где ключевыми элементами являются свойства (props), методы жизненного цикла и рендеринг.

import { define, props, h } from 'skatejs';

class MyComponent extends HTMLElement {
  static props = {
    message: props.string
  };

  renderCallback() {
    return h('div', null, `Сообщение: ${this.message}`);
  }
}

define(MyComponent);

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

  • static props определяет реактивные свойства компонента.
  • renderCallback отвечает за рендеринг и автоматически вызывается при изменении свойств.
  • h — функция для декларативного создания DOM-структуры, аналог JSX.

Свойства и реактивность

Свойства компонентов — это основа SkateJS. Они позволяют связывать данные с визуальной частью компонента и реагировать на их изменения.

static props = {
  count: {
    type: Number,
    attribute: true,
    default: 0
  }
};
  • type задает тип свойства.
  • attribute позволяет синхронизировать свойство с HTML-атрибутом.
  • default устанавливает значение по умолчанию.

Изменение свойства вызывает повторный рендер компонента без необходимости вручную управлять DOM.

this.count += 1; // Автоматически перерендерит компонент

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

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

  • connectedCallback() — вызывается при вставке компонента в DOM.
  • disconnectedCallback() — вызывается при удалении из DOM.
  • renderCallback() — основной метод рендеринга, вызывается при изменении свойств.
  • updatedCallback(prevProps) — вызывается после изменения свойств, предоставляет старые значения.

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

updatedCallback(prevProps) {
  if (prevProps.count !== this.count) {
    console.log(`Счетчик изменился: ${this.count}`);
  }
}

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

Работа с событиями

SkateJS упрощает работу с событиями, позволяя привязывать обработчики прямо к элементам через функцию h:

renderCallback() {
  return h('button', { onclick: () => this.increment() }, `Нажато ${this.count} раз`);
}

increment() {
  this.count++;
}
  • Обработчики событий определяются в объекте атрибутов элемента.
  • Можно использовать стрелочные функции для сохранения контекста компонента.

Инкапсуляция и Shadow DOM

SkateJS автоматически поддерживает Shadow DOM, что позволяет скрывать внутреннюю структуру компонента и стили:

import { define, props, h, withComponent } from 'skatejs';

class ShadowComponent extends withComponent(HTMLElement) {
  static props = { text: props.string };

  static get observedAttributes() {
    return ['text'];
  }

  renderCallback() {
    return h('div', { style: 'color: red;' }, this.text);
  }
}

define(ShadowComponent);
  • Все стили и DOM внутри компонента изолированы от глобального контекста.
  • Это предотвращает конфликты CSS и нежелательные взаимодействия с другими элементами страницы.

Составные и вложенные компоненты

SkateJS позволяет создавать компоненты, которые включают другие компоненты:

class ParentComponent extends HTMLElement {
  renderCallback() {
    return h('div', null, 
      h('child-component', { message: 'Привет' })
    );
  }
}

define(ParentComponent);
  • Каждый вложенный компонент работает независимо, сохраняя свою реактивность.
  • Свойства передаются через атрибуты или объект props, обеспечивая гибкую конфигурацию.

Организация кода

Для больших проектов рекомендуется использовать модульную структуру:

/components
  /button
    button.js
    button.css
  /counter
    counter.js
    counter.css
  • Каждый компонент в отдельной папке.
  • CSS для компонента изолирован внутри Shadow DOM.
  • Логика и рендер разделены для удобства поддержки и тестирования.

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

static props = {
  count: props.number
};

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

Интеграция с внешними библиотеками

SkateJS легко интегрируется с библиотеками для состояния или анимаций. Например, с RxJS или GSAP можно связать реактивные свойства с потоками данных или анимациями, не нарушая инкапсуляцию компонентов.

import { fromEvent } from 'rxjs';

connectedCallback() {
  this.subscription = fromEvent(this, 'click').subscribe(() => this.increment());
}

disconnectedCallback() {
  this.subscription.unsubscribe();
}

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

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

  1. Определение свойств (props) — реактивные данные.
  2. Методы жизненного цикла — управление вставкой, удалением и обновлением.
  3. Рендеринг (renderCallback) — создание DOM.
  4. Обработка событий — методы компонента или стрелочные функции.
  5. Инкапсуляция через Shadow DOM — стили и структура защищены.
  6. Модульность — каждый компонент в отдельной папке с собственной логикой и стилями.

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