GrVideoPlayer
Берут, когда ролик внутри страницы продукта.
Когда брать
- ролик внутри страницы продукта — обзор возможностей, где вид плеера обязан совпадать с остальным интерфейсом;
- запись встречи или урока в личном кабинете: нужна перемотка с клавиатуры и предсказуемая позиция;
- короткое видео-подтверждение в заявке — снятое тут же и проигранное рядом;
- тёмная и светлая тема на одной странице: нативные элементы управления тему не знают.
Когда взять другое
| Нужно | Берите |
|---|---|
| Снять кадр камерой | GrCameraCapture |
| Показать картинку во весь экран | GrImageViewer |
| Плитка вложения в ленте | GrFilePreview |
Полный экран запрашивается у рамки, а не у видео
requestFullscreen на самом <video> отдаёт браузеру его собственный
интерфейс: наши кнопки, подписи и клавиатура исчезают ровно там, где нужны
больше всего — на весь экран. Поэтому запрос идёт у корневого элемента, и
панель едет вместе с кадром.
Полоса буфера берётся вокруг позиции
Браузер держит несколько загруженных диапазонов, и после перемотки назад последний из них относится к другому куску ролика. Полоса, нарисованная по последнему, прыгала бы вперёд на пустом месте, обещая загруженное там, где его нет. Берётся диапазон, накрывающий текущую позицию.
Длительность известна не всегда
У потоковой записи — сделанной MediaRecorder, пришедшей из эфира — длительности
нет в заголовке, и браузер отдаёт NaN. Полоса прогресса в этом случае не
рисуется вовсе, а подпись показывает одно текущее время: «1:05 / 0:00» обещало бы
конец, которого запись не знает.
Время в подписи, а не доля
Дорожка объявляет себя диктору через aria-valuetext — «1:05 / 2:00». Голое
aria-valuenow дало бы «65 из 120»: формально верно и бесполезно.
Секунды всегда двузначные (1:05, не 1:5), а часы появляются, только когда
они есть: 0:00:07 у семисекундного ролика читается как ошибка.
Звук выключен, если нужен автозапуск
autoplay без muted браузеры блокируют — политика автовоспроизведения не
обходится ничем. Компонент этого не скрывает: muted остаётся отдельным пропом,
и решение «запускать без звука» принимает приложение, а не библиотека.
Границы
- нет качества и дорожек. Выбор потока (HLS, DASH), субтитры и звуковые дорожки — работа медиа-движка, а не элементов управления; их подключают сторонним плеером;
- нет плейлиста. Компонент показывает один ролик; очередь и переходы между роликами остаются приложению;
- нет скорости воспроизведения. Она нужна редко и стоит ещё одного меню на панели, где место дороже.
Установка
npm i @feugene/granularity-mediaИмпорт
import { GrVideoPlayer } from '@feugene/granularity-media/components/GrVideoPlayer'API
API этого компонента ещё не посчитан: генератор витрины пока обходит только ядро. Пока его нет, справочник — в документации пакета.
Примеры 1
Basic
<script setup lang="ts">
import { ref } from 'vue'
import { GrBadge } from '@feugene/granularity'
/**
* Ролик лежит в `public/demo` и собирается скриптом
* `scripts/generate-demo-video.mjs`: витрина обязана работать без сети, а
* тащить бинарь из внешнего источника — значит зависеть от чужого хостинга.
*/
const source = `${import.meta.env.BASE_URL}demo/sample.webm`
const state = ref<'ready' | 'playing' | 'paused' | 'ended'>('ready')
const position = ref(0)
function onTime(current: number) {
position.value = current
}
</script>
<template>
<div class="grid gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(0,300px)]">
<GrVideoPlayer
:src="source"
:aspect-ratio="16 / 9"
muted
@play="state = 'playing'"
@pause="state = 'paused'"
@ended="state = 'ended'"
@timeupdate="onTime"
/>
<div class="showcase-demo-panel grid content-start gap-3 rounded-[var(--gr-radius-lg)] border p-4">
<p class="showcase-demo-text text-sm">
Состояние: <GrBadge size="sm" tone="neutral">{{ state }}</GrBadge>
</p>
<p class="showcase-demo-text text-sm">
Позиция: <strong>{{ position.toFixed(1) }} с</strong>
</p>
<p class="showcase-demo-text text-sm">
Элементы управления свои, а не браузерные: нативные выглядят по-разному в каждом
браузере и не знают ни про темы, ни про размеры дизайн-системы.
</p>
<p class="showcase-demo-text text-sm">
Клавиатура работает, когда плеер в фокусе: пробел — пуск и пауза, стрелки влево и
вправо — перемотка на пять секунд, <code>Home</code> и <code>End</code> — к началу и
концу, <code>M</code> — звук, <code>F</code> — во весь экран.
</p>
<p class="showcase-demo-text text-sm">
Длительность плеер берёт у браузера и не выдумывает: у потоковой записи её в заголовке
нет, и тогда вместо «1:05 / 0:00» показывается одно текущее время, а полоса не рисуется
вовсе — обещать конец, которого запись не знает, нельзя.
</p>
</div>
</div>
</template>