Stencil — это прогрессивный фреймворк для создания веб-компонентов с использованием современных стандартов Web Components и TypeScript. Одной из важных задач при разработке сложных интерфейсов является сбор и обработка данных о действиях пользователей для последующей аналитики. Рассмотрим, как реализовать систему пользовательской аналитики внутри компонентов Stencil.
Для начала необходимо определить, какие события и действия пользователя будут отслеживаться. Обычно это:
В Stencil это удобно делать с использованием декораторов и слушателей событий.
import { Component, h, Listen } from '@stencil/core';
@Component({
tag: 'user-tracker',
styleUrl: 'user-tracker.css',
shadow: true,
})
export class UserTracker {
@Listen('click', { capture: true })
handleClick(event: MouseEvent) {
const target = event.target as HTMLElement;
console.log('Click on:', target.tagName, target.id || target.className);
this.sendAnalytics({ type: 'click', element: target.tagName });
}
sendAnalytics(data: Record<string, any>) {
fetch('https://analytics.example.com/track', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
}
render() {
return <slot />;
}
}
В примере выше используется декоратор
@Listen, который позволяет перехватывать события
на уровне компонента. Это удобно для глобального отслеживания кликов без
необходимости добавлять обработчики на каждый элемент вручную.
Stencil-компоненты могут отправлять данные на сторонние аналитические платформы, такие как Google Analytics, Mixpanel или Amplitude. Для этого достаточно обернуть вызовы API в отдельный сервис:
export class AnalyticsService {
static trackEvent(eventName: string, payload: Record<string, any>) {
// Пример для Google Analytics 4
if ((window as any).gtag) {
(window as any).gtag('event', eventName, payload);
}
}
}
В компоненте можно подключать сервис:
import { AnalyticsService } from './analytics-service';
handleClick(event: MouseEvent) {
const target = event.target as HTMLElement;
AnalyticsService.trackEvent('click', { element: target.tagName });
}
Такой подход разделяет логику отображения и аналитику, делая код компонентов более чистым и поддерживаемым.
Для анализа пользовательского поведения важно фиксировать не только
события DOM, но и изменения состояния компонентов. В
Stencil для этого удобно использовать декоратор
@Watch:
import { Component, h, State, Watch } from '@stencil/core';
@Component({
tag: 'toggle-switch',
styleUrl: 'toggle-switch.css',
shadow: true,
})
export class ToggleSwitch {
@State() isOn: boolean = false;
@Watch('isOn')
onToggleChange(newValue: boolean, oldValue: boolean) {
console.log(`Toggle changed from ${oldValue} to ${newValue}`);
AnalyticsService.trackEvent('toggle_change', { newValue, oldValue });
}
toggle() {
this.isOn = !this.isOn;
}
render() {
return <button onCl ick={() => this.toggle()}>{this.isOn ? 'ON' : 'OFF'}</button>;
}
}
Использование @Watch позволяет отслеживать любые
изменения состояния, что критично для компонентов с
интерактивным поведением.
При внедрении аналитики важно учитывать производительность:
let scrollTimeout: number;
window.addEventListener('scroll', () => {
clearTimeout(scrollTimeout);
scrollTimeout = window.setTimeout(() => {
AnalyticsService.trackEvent('scroll', { position: window.scrollY });
}, 200);
});
Пакетная отправка данных. Для высокой нагрузки можно собирать события в массив и отправлять пакетами раз в N секунд.
Асинхронная отправка. Использование
navigator.sendBeacon или асинхронных fetch-запросов
предотвращает блокировку основного потока рендеринга.
Для точной аналитики требуется идентификация пользователей. В Stencil это реализуется через локальное хранение идентификатора:
function getUserId(): string {
let userId = localStorage.getItem('userId');
if (!userId) {
userId = crypto.randomUUID();
localStorage.setItem('userId', userId);
}
return userId;
}
Все события можно привязывать к этому идентификатору:
AnalyticsService.trackEvent('click', { userId: getUserId(), element: 'button' });
Stencil часто использует Shadow DOM, что усложняет глобальный поиск элементов. Для аналитики:
composedPath(), чтобы получить путь
события через shadow root:@Listen('click', { capture: true })
handleShadowClick(event: MouseEvent) {
const path = event.composedPath() as HTMLElement[];
const target = path.find(el => el.tagName === 'BUTTON');
if (target) {
AnalyticsService.trackEvent('shadow_click', { element: target.tagName });
}
}
Данные, собранные через Stencil-компоненты, можно использовать для:
Для визуализации удобно экспортировать события в JSON и подключать библиотеки вроде Chart.js, D3.js или Recharts.
Этот подход обеспечивает полную и гибкую систему user analytics на основе Stencil, позволяя отслеживать клики, состояния, события Shadow DOM, а также интегрироваться с внешними сервисами и визуализировать данные.