Я работаю над дизайном контейнера для видео с использованием HTML, CSS и JavaScript, и хочу реализовать функцию, которая будет автоматически переключать видео при прокрутке, подобно тому, как это делает YouTube Shorts.
У меня есть базовый дизайн, где я загружаю видео вместе с кнопками взаимодействия, такими как подписка, лайк, комментарий и поделиться. Однако мне нужна помощь с функциональностью JavaScript, которая позволяет видео меняться, когда пользователь прокручивает мимо текущего видео.
Вот моя HTML-структура:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Адаптивный дизайн Shorts</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<!-- Видео секция -->
<div class="video-container">
<video id="video-player" src="videos/video1.mp4" controls></video>
<!-- Кнопка подписки -->
<button class="follow-button">Подписаться</button>
<!-- Кнопки взаимодействия на проигрывателе видео -->
<div class="actions">
<div class="action-button like">
<span><i class="fa-regular fa-heart"></i></span>
<span>452</span>
</div>
<div class="action-button comment">
<span><i class="fa-regular fa-comment"></i></span>
<span>6</span>
</div>
<div class="action-button share">
<span><i class="fa-solid fa-share"></i></span>
<span>Поделиться</span>
</div>
</div>
</div>
</div>
<script src="scripts.js"></script>
</body>
</html>
А вот и мой CSS:
/* Глобальные стили */
body, html {
margin: 0;
padding: 0;
overflow-x: hidden;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
overflow: hidden;
}
.video-container {
width: 100%;
height: 100%;
}
video {
width: 100%;
height: 100%;
object-fit: cover;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: Arial, sans-serif;
}
body {
background-color: #181818;
color: white;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 20px;
height: 100vh;
}
/* Видео секция */
.video-container {
width: 100%;
max-width: 400px;
height: 800px;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
video {
width: 100%;
height: 100%;
border-radius: 10px;
position: relative;
}
/* Кнопка подписки */
.follow-button {
position: absolute;
top: 10px;
right: 10px;
padding: 8px 12px;
background-color: #ff0000;
color: white;
border: none;
border-radius: 20px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.3s ease;
}
.follow-button:hover {
background-color: #cc0000;
}
/* Секция действий: кнопки справа от видео */
.actions {
position: absolute;
right: 10px;
top: 20%;
display: flex;
flex-direction: column;
align-items: center;
}
.action-button {
margin: 10px 0;
color: white;
text-align: center;
cursor: pointer;
padding: 10px;
background-color: rgba(0, 0, 0, 0.5); /* Полупрозрачный фон */
border-radius: 50%;
width: 50px;
height: 50px;
opacity: 0.8; /* Эффект прозрачности */
transition: opacity 0.3s ease;
}
.action-button:hover {
opacity: 1;
}
/* Убедитесь, что иконкиCentered внутри кнопок */
.action-button span {
display: block;
}
/* Секция подписки */
.subscribe-section {
display: flex;
align-items: center;
justify-content: space-between;
background-color: #333;
padding: 10px 15px;
border-radius: 10px;
max-width: 400px;
width: 100%;
margin-top: 10px;
}
.profile-pic {
width: 50px;
height: 50px;
border-radius: 50%;
}
.subscribe-info {
flex-grow: 1;
padding-left: 10px;
}
.subscribe-button {
padding: 10px 15px;
background-color: #ff0000;
border: none;
border-radius: 5px;
color: white;
cursor: pointer;
}
/* Адаптивные медиа-запросы */
@media (max-width: 768px) {
.actions {
right: 5px;
top: 15%;
}
.subscribe-section {
flex-direction: column;
align-items: center;
padding: 15px;
}
.profile-pic {
width: 40px;
height: 40px;
}
.subscribe-button {
margin-top: 10px;
width: 100%;
}
}
@media (max-width: 480px) {
.video-container {
max-width: 100%;
}
.actions {
position: static;
flex-direction: row;
width: 100%;
justify-content: space-evenly;
}
}
Идея состоит в том, чтобы автоматически переключаться между несколькими видео на основе взаимодействия пользователя с прокруткой. У меня есть массив видео, и мне нужно загружать следующее при прокрутке. Вот JavaScript, который я пробовал:
document.addEventListener('DOMContentLoaded', function() {
const videos = [
"videos/video1.mp4",
"videos/video2.mp4",
"videos/video3.mp4",
// Добавьте больше видео по мере необходимости
];
let currentVideoIndex = 0;
const videoPlayer = document.getElementById('video-player');
// Функция для загрузки следующего видео
function loadNextVideo() {
currentVideoIndex++;
if (currentVideoIndex >= videos.length) {
currentVideoIndex = 0; // Вернуться к первому видео
}
videoPlayer.src = videos[currentVideoIndex];
videoPlayer.play();
}
// Использование IntersectionObserver для определения, когда пользователь прокручивает мимо текущего видео
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Если текущее видео полностью видно, воспроизведите его
videoPlayer.play();
} else {
// Если видео больше не видно, загрузите следующее видео
loadNextVideo();
}
});
}, {
threshold: 0.75 // Видео считается видимым, когда 75% его отображается на экране
});
// Наблюдение за контейнером видео
observer.observe(videoPlayer);
});
Проблема:
Я хочу добиться такого же опыта, как в YouTube Shorts, где каждое прокручивание напрямую переходит к следующему видео. Однако я не уверен, является ли этот подход с IntersectionObserver лучшим для этого случая, или есть лучшее решение.
Какой будет лучший способ реализовать такое переключение видео на основе прокрутки?
Правка:
мой обновленный js:
console.log("Scroller");
// Определите массив видео
const videos = [
"videos/video1.mp4",
"videos/video2.mp4",
"videos/video3.mp4",
// Добавьте больше видео по мере необходимости
];
// Получите элементы контейнера и проигрывателя видео
const container = document.querySelector('.container');
const videoPlayer = document.getElementById('video-player');
// Инициализируйте индекс текущего видео
let currentVideoIndex = 0;
// Инициализируйте флаг, чтобы указать, взаимодействовал ли пользователь с документом
let userHasInteracted = false;
// Добавьте слушателя событий прокрутки к контейнеру
container.addEventListener('scroll', (e) => {
// Получите смещение видео и высоту
const videoOffset = videoPlayer.offsetTop;
const videoHeight = videoPlayer.offsetHeight;
// Получите положение прокрутки и направление
const scrollPosition = container.scrollTop;
const scrollDirection = e.deltaY > 0 ? 'down' : 'up';
// Проверьте, прокрутил ли пользователь вниз и текущее видео больше не видно
if (scrollDirection === 'down' && scrollPosition > videoOffset + videoHeight - 20) {
// Загрузите следующее видео
loadNextVideo();
}
});
// Функция для загрузки следующего видео
function loadNextVideo() {
// Увеличьте индекс текущего видео
currentVideoIndex++;
// Вернуться к первому видео, если мы достигли конца массива
if (currentVideoIndex >= videos.length) {
currentVideoIndex = 0;
}
// Обновите источник воспроизводителя видео
videoPlayer.src = videos[currentVideoIndex];
// Если пользователь взаимодействовал с документом, воспроизведите видео автоматически
if (userHasInteracted) {
videoPlayer.play();
}
}
// Добавьте слушателя событий к документу, чтобы слушать взаимодействие пользователя
document.addEventListener('click', () => {
// Установите флаг, чтобы указать, что пользователь взаимодействовал с документом
userHasInteracted = true;
// Если видео не воспроизводится, воспроизведите его
if (!videoPlayer.paused) {
videoPlayer.play();
}
});
// Инициализируйте проигрыватель видео с первым видео
videoPlayer.src = videos[0];
Ответ
Чтобы реализовать функцию переключения видео на основе прокрутки, как в YouTube Shorts, мы можем воспользоваться обработчиком событий прокрутки в сочетании с некоторыми простыми математическими расчетами. Ниже представлен полный пример кода, который будет реализовывать эту функциональность.
Полный Код:
HTML
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Дизайн коротких видео</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<div class="video-container">
<video id="video-player" src="videos/video1.mp4" controls></video>
<button class="follow-button">Подписаться</button>
<div class="actions">
<div class="action-button like">
<span><i class="fa-regular fa-heart"></i></span>
<span>452</span>
</div>
<div class="action-button comment">
<span><i class="fa-regular fa-comment"></i></span>
<span>6</span>
</div>
<div class="action-button share">
<span><i class="fa-solid fa-share"></i></span>
<span>Поделиться</span>
</div>
</div>
</div>
</div>
<script src="scripts.js"></script>
</body>
</html>
CSS
/* Общие стили */
body, html {
margin: 0;
padding: 0;
overflow-x: hidden;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
overflow-y: scroll; /* Разрешить вертикальную прокрутку */
}
.video-container {
width: 100%;
height: 100vh; /* Высота контейнера равна высоте экрана */
}
video {
width: 100%;
height: 100%;
object-fit: cover;
}
.actions {
position: absolute;
right: 10px;
top: 20%;
display: flex;
flex-direction: column;
align-items: center;
}
.action-button {
margin: 10px 0;
}
JavaScript
document.addEventListener('DOMContentLoaded', function() {
const videos = [
"videos/video1.mp4",
"videos/video2.mp4",
"videos/video3.mp4",
// Добавьте больше видео при необходимости
];
const videoPlayer = document.getElementById('video-player');
let currentVideoIndex = 0;
// Функция для загрузки следующего видео
function loadNextVideo() {
currentVideoIndex++;
if (currentVideoIndex >= videos.length) {
currentVideoIndex = 0; // Зацикливание на первом видео
}
videoPlayer.src = videos[currentVideoIndex];
videoPlayer.play();
}
// Обработчик события прокрутки
const container = document.querySelector('.container');
container.addEventListener('wheel', (event) => {
// Проверяем направление прокрутки
if (event.deltaY > 0) {
loadNextVideo();
} else if (event.deltaY < 0) {
currentVideoIndex--;
if (currentVideoIndex < 0) {
currentVideoIndex = videos.length - 1; // Зацикливание на последнем видео
}
videoPlayer.src = videos[currentVideoIndex];
videoPlayer.play();
}
// Предотвращаем стандартное поведение прокрутки
event.preventDefault();
});
// Инициализация первого видео
videoPlayer.src = videos[currentVideoIndex];
});
Объяснение Код
-
HTML-структура: Здесь создается основной контейнер с видео и кнопками взаимодействия. Видео прописывается через элемент
<video>
, что позволяет использовать его возможности. -
Стили CSS: Контейнеру и видео задается полная высота экрана, что позволяет прокручивать контейнер и видеть полное видео.
- JavaScript логика:
- Массив с видео файлами.
- При прокрутке колесом
wheel
определяем направление. Если прокрутка вниз, загружаем следующее видео, если вверх – загружаем предыдущее. - Используется
event.preventDefault()
, чтобы предотвратить стандартное поведение прокрутки страницы, тем самым обеспечивая фокус на видео.
Итоги
Это решение позволяет вам переключать видео прокручивая страницу, создавая эффект, схожий с YouTube Shorts. В дальнейшем вы можете добавлять дополнительные функции, такие как управления музыкой, плейлистами и событиями на конце видео.