SkateJS — это библиотека для построения веб-компонентов на основе стандарта Custom Elements с упором на реактивность, простоту и переиспользуемость. В основе лежит концепция компонентов как объектов с жизненным циклом, что позволяет структурировать интерфейс в виде независимых и легко тестируемых модулей.
Компонент создается с помощью функции skate и
описывается через объект с ключевыми свойствами:
props — определяет свойства компонента
с типами и значениями по умолчанию.render — функция рендеринга,
возвращающая разметку (обычно через JSX или шаблонную строку).connected / disconnected
— методы жизненного цикла, вызываемые при добавлении или удалении
элемента из DOM.updated — метод, вызываемый при
изменении свойств компонента.Пример минимального компонента:
import { skate } from 'skatejs';
skate('my-counter', {
props: {
count: { type: Number, default: 0 }
},
render({ count }) {
return `<div>Счетчик: ${count}</div>`;
},
connected() {
console.log('Компонент добавлен в DOM');
},
updated(prev, next) {
console.log(`Счетчик изменился с ${prev.count} на ${next.count}`);
}
});
Программная навигация в контексте SkateJS — это управление состоянием и переходами между страницами или состояниями интерфейса без полной перезагрузки документа. В современных приложениях чаще всего реализуется через Router-компоненты, которые слушают изменения URL или внутреннего состояния и рендерят соответствующие компоненты.
Состояние маршрутизации обычно хранится в виде объекта с ключами:
const routes = {
'/': HomeComponent,
'/about': AboutComponent,
'/profile/:id': ProfileComponent
};
SkateJS позволяет связать состояние маршрута с компонентами через
реактивные свойства и методы жизненного цикла. При изменении URL можно
программно обновить свойство currentRoute
компонента-роутера:
skate('app-router', {
props: {
currentRoute: { type: String, default: '/' }
},
render({ currentRoute }) {
const Component = routes[currentRoute] || NotFoundComponent;
return `<${Component}></${Component}>`;
}
});
Для динамических маршрутов (/profile/:id) важно уметь
извлекать параметры. В SkateJS это достигается через парсинг
URL и реактивное обновление свойств:
function parseRoute(url) {
const match = url.match(/\/profile\/(\d+)/);
if (match) {
return { route: '/profile/:id', id: match[1] };
}
return { route: url };
}
skate('app-router', {
props: {
currentRoute: { type: String, default: '/' },
routeParams: { type: Object, default: () => ({}) }
},
connected() {
window.addEventListener('popstate', this.onRouteChange.bind(this));
this.onRouteChange();
},
disconnected() {
window.removeEventListener('popstate', this.onRouteChange.bind(this));
},
onRouteChange() {
const { route, id } = parseRoute(window.location.pathname);
this.currentRoute = route;
this.routeParams = id ? { id } : {};
},
render({ currentRoute, routeParams }) {
const Component = routes[currentRoute] || NotFoundComponent;
return `<${Component} .params=${JSON.stringify(routeParams)}></${Component}>`;
}
});
Для навигации без перезагрузки страницы используется метод
history.pushState или history.replaceState.
Skate-компонент роутера реагирует на эти изменения через
popstate:
function navigateTo(path) {
history.pushState({}, '', path);
window.dispatchEvent(new Event('popstate'));
}
// Пример кнопки навигации внутри компонента
skate('nav-link', {
props: { href: String },
render({ href }) {
return `<a href="${href}" oncl ick="event.preventDefault(); navigateTo('${href}')">Перейти</a>`;
}
});
В крупных приложениях важно подгружать компоненты по мере необходимости, чтобы уменьшить первоначальный размер бандла. SkateJS поддерживает асинхронный рендеринг через динамический импорт:
const routes = {
'/': () => import('./HomeComponent.js'),
'/about': () => import('./AboutComponent.js')
};
skate('app-router', {
props: { currentRoute: String },
async render({ currentRoute }) {
const loader = routes[currentRoute];
if (!loader) return '<div>Страница не найдена</div>';
const module = await loader();
const Component = module.default;
return `<${Component}></${Component}>`;
}
});
Такой подход позволяет сочетать реактивность SkateJS и lazy-loading, обеспечивая оптимальную производительность и гибкость навигации.
Для полноценной SPA-навигации важно синхронизировать маршруты с
глобальным состоянием. SkateJS легко интегрируется с Redux, MobX
или Zustand. Свойства компонента могут быть обертками
над состоянием, автоматически вызывающими render
при изменении:
import { state } from './store.js';
skate('app-router', {
props: { currentRoute: String },
render() {
const current = state.route;
const Component = routes[current] || NotFoundComponent;
return `<${Component}></${Component}>`;
}
});
Любое изменение state.route мгновенно обновляет
интерфейс без дополнительных действий, сохраняя реактивность и
предсказуемость.
Для более сложных интерфейсов можно управлять анимацией переходов
между маршрутами через CSS или Web Animations API, используя
методы жизненного цикла connected,
disconnected и updated:
skate('page-transition', {
render() {
return `<slot></slot>`;
},
updated(prev, next) {
const el = this.shadowRoot.querySelector('slot');
if (prev.currentRoute !== next.currentRoute) {
el.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 300 });
}
}
});
Такой подход позволяет объединить программную навигацию и визуальные эффекты, сохраняя модульность компонентов.
SkateJS предоставляет полный набор инструментов для построения реактивной, управляемой программно навигации, где каждый компонент становится автономным, а состояние интерфейса и URL синхронизированы без лишних перезагрузок страницы.