Atomico — это современная библиотека для построения веб-компонентов на JavaScript с реактивной моделью данных, похожей на React, но с упором на Web Components. Видео-компоненты в Atomico позволяют создавать интерактивные плееры с кастомной логикой управления, обработкой событий и интеграцией с другими частями приложения.
В Atomico компонент создается через функцию component.
Для видео-компонента минимальный пример выглядит так:
import { component, html, useState } from "atomico";
function VideoPlayer() {
const [playing, setPlaying] = useState(false);
let videoRef;
const togglePlay = () => {
if (!videoRef) return;
if (playing) {
videoRef.pause();
} else {
videoRef.play();
}
setPlaying(!playing);
};
return html`
<div>
<video
ref=${(el) => videoRef = el}
src="sample.mp4"
width="640"
controls>
</video>
<button oncl ick=${togglePlay}>
${playing ? "Pause" : "Play"}
</button>
</div>
`;
}
customElements.define("video-player", component(VideoPlayer));
Ключевые моменты:
useState управляет состоянием воспроизведения.ref используется для получения ссылки на DOM-элемент
<video>.html позволяет возвращать шаблон с реактивными
переменными.Видео-тэг поддерживает множество событий: play,
pause, ended, timeupdate и
другие. В Atomico их удобно обрабатывать через
on<Event> в шаблоне или через
addEventListener на ссылке ref.
Пример отслеживания прогресса воспроизведения:
function VideoProgress() {
const [time, setTime] = useState(0);
let videoRef;
const handleTimeUpdate = (e) => {
setTime(videoRef.currentTime);
};
return html`
<div>
<video
ref=${(el) => videoRef = el}
src="sample.mp4"
width="640"
ontimeUPDATE=${handleTimeUpdate}>
</video>
<div>Прошло времени: ${time.toFixed(2)} сек</div>
</div>
`;
}
Особенности:
on<Event>.useState автоматически
перерисовывает компонент.Atomico позволяет объявлять свойства компонента через
props, что упрощает повторное использование:
function VideoPlayer({ src, width = 640 }) {
const [playing, setPlaying] = useState(false);
let videoRef;
const togglePlay = () => {
if (!videoRef) return;
if (playing) videoRef.pause();
else videoRef.play();
setPlaying(!playing);
};
return html`
<div>
<video ref=${(el) => videoRef = el} src=${src} width=${width}></video>
<button oncl ick=${togglePlay}>
${playing ? "Pause" : "Play"}
</button>
</div>
`;
}
VideoPlayer.props = {
src: String,
width: Number
};
customElements.define("video-player", component(VideoPlayer));
Преимущества:
Можно полностью отказаться от стандартных контролов
<video> и создать свои кнопки управления:
function CustomControlsVideo({ src }) {
const [playing, setPlaying] = useState(false);
const [volume, setVolume] = useState(1);
let videoRef;
const togglePlay = () => {
if (!videoRef) return;
if (playing) videoRef.pause();
else videoRef.play();
setPlaying(!playing);
};
const changeVolume = (e) => {
if (!videoRef) return;
videoRef.volume = e.target.value;
setVolume(e.target.value);
};
return html`
<div>
<video ref=${(el) => videoRef = el} src=${src} width="640"></video>
<div>
<button oncl ick=${togglePlay}>
${playing ? "Pause" : "Play"}
</button>
<input type="range" min="0" max="1" step="0.01" value=${volume} oncha nge=${changeVolume}>
</div>
</div>
`;
}
CustomControlsVideo.props = { src: String };
customElements.define("custom-video-player", component(CustomControlsVideo));
Особенности реализации:
input type="range" управляет громкостью.volume синхронизирует ползунок и
видео.Atomico позволяет легко использовать несколько экземпляров компонентов с разными свойствами:
<video-player src="video1.mp4" width="320"></video-player>
<video-player src="video2.mp4" width="480"></video-player>
<custom-video-player src="video3.mp4"></custom-video-player>
Каждый компонент сохраняет собственное состояние
playing, volume и другие параметры, не влияя
на остальные экземпляры.
Для более сложных видео-плееров важно отслеживать, когда видео полностью загружено:
function AsyncVideo({ src }) {
const [ready, setReady] = useState(false);
let videoRef;
const handleLoadedData = () => setReady(true);
return html`
<div>
<video ref=${(el) => videoRef = el} src=${src} width="640" onloadedd ata=${handleLoadedData}></video>
${ready ? html`<div>Видео готово к воспроизведению</div>` : html`<div>Загрузка...</div>`}
</div>
`;
}
AsyncVideo.props = { src: String };
customElements.define("async-video", component(AsyncVideo));
Преимущества:
Atomico поддерживает scoped CSS через шаблон css или
внешние стили. Для видео-компонентов удобно использовать CSS-переменные
и анимации при изменении состояния:
import { css } from "atomico";
const videoStyle = css`
video {
border-radius: 12px;
transition: transform 0.3s;
}
video:hover {
transform: scale(1.05);
}
button {
margin-top: 8px;
padding: 4px 12px;
border: none;
background-color: #007acc;
color: white;
cursor: pointer;
border-radius: 4px;
}
`;
function StyledVideo({ src }) {
const [playing, setPlaying] = useState(false);
let videoRef;
const togglePlay = () => {
if (!videoRef) return;
if (playing) videoRef.pause();
else videoRef.play();
setPlaying(!playing);
};
return html`
<div class=${videoStyle}>
<video ref=${(el) => videoRef = el} src=${src} width="640"></video>
<button oncl ick=${togglePlay}>${playing ? "Pause" : "Play"}</button>
</div>
`;
}
StyledVideo.props = { src: String };
customElements.define("styled-video", component(StyledVideo));
Результат:
Этот подход позволяет строить гибкие, масштабируемые и полностью настраиваемые видео-компоненты, интегрируемые в любой веб-проект с минимальными зависимостями и высокой реактивностью.