Эта статья была рецензирована Томом Греко и Марком Таулером . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!
Поскольку поддержка родного элемента видео и его API довольно обширна , сейчас самое время взглянуть на способы использования видео для создания чего-то интересного и интерактивного для ваших пользователей.
В этой статье мы рассмотрим основы API, и после того, как мы получим ориентиры, мы будем работать на практическом примере. Это будет мульти-видео слайдер, в котором видео воспроизводятся одно за другим, плавно загружаются и анимируются по мере воспроизведения.
Видео API — краткое введение
По сути, когда мы говорим о Video API, мы действительно говорим о Media API — API JavaScript, который позволяет вам взаимодействовать с аудио и видео элементами на веб-странице.
Этот API реализует интерфейс под названием HTMLMediaElement, который добавляет свойства , методы и события, необходимые для поддержки основных операций, общих для аудио и видео (таких как загрузка мультимедиа, изменение позиции поиска, завершение воспроизведения и т. Д.). Он расширяется как HTMLVideoElement, так и HTMLAudioElement, которые предоставляют свои собственные специальные свойства и методы.
В основном нас интересует элемент video поэтому мы сосредоточимся на взаимодействии с этой частью API. Чтобы ознакомиться с API, вы можете посетить страницу интерактивного примера HTML5-видео, на которой представлены наиболее часто используемые элементы.
Поддержка браузера
Хотя Chrome, Firefox, Safari, Opera и Internet Explorer поддерживают видеоэлемент, они различаются по форматам, которые они могут воспроизводить, у каждого браузера есть список поддерживаемых видеоформатов, который также может быть основан на версии самого браузера.
На момент написания статьи все современные настольные и мобильные браузеры будут воспроизводить формат mp4 . Кроме того, большинство браузеров будут иметь длительную поддержку любого (или обоих) форматов ogg или webm . Вот полный обзор текущего состояния поддержки.
Хотя вы можете обойтись только предоставлением версии mp4 вам, вероятно, следует включить форматы ogg и webm в качестве комплексного решения.
Интерактивная видео-витрина
Мы будем создавать функцию демонстрации, используя элемент video . Наша витрина будет воспроизводить серию небольших видеоклипов подряд и запускать анимацию в определенное время. Используя такой видеоэлемент, мы исследуем некоторые его свойства, методы и события и показываем уровень контроля, которого вы можете достичь с помощью этого API.
Как всегда, вы можете найти код для этого руководства в нашем репозитории GitHub , а также демонстрацию готовой демонстрации в конце статьи.
Структурирование HTML-макета
В нашем примере с ползунком каждое видео будет воспроизводиться одно за другим, при этом во время воспроизведения будут появляться соответствующие заголовки для каждого видео. Если мы не поддерживаем воспроизведение видео / находимся на мобильном устройстве, мы вернемся к статическому изображению с заголовком текста.
Создайте контурную обертку для своего слайдера и добавьте в нее каждый раздел видео, который вы хотите определить
<!--Main video wrapper--> <div class="video-wrapper" id="video-container"> <!--first video--> <div class="video-container"></div> <!--second video--> <div class="video-container"></div> <!--Nth video--> ... </div>
Разметка для каждого раздела видео
Для каждого видео, которое мы хотим воспроизвести, нам нужно будет настроить несколько элементов, чтобы мы могли отображать видео, затемнять элементы заголовка и отслеживать общий ход видео.
<!--Progress bar--> <div class="progress-bar"> <div class="progress"> <div class="progress-inner"> <span class="progress-time"></span> <span class="progress-value"></span> </div> </div> </div> <!--Progress bar overlay--> <div class="progress-overlay"></div> <!--Video Elements--> <video preload="none"> <source src="videos/video1/video1.mp4" type="video/mp4"> <source src="videos/video1/video1.webm" type="video/webm"> <source src="videos/video1/video1.ogg" type="video/ogg"> </video> <!--Video overlay--> <div class="overlay"></div> <!--Caption Elements--> <div class="caption"> <h1 data-animation-percent="10">Amazing New Adventures</h1> <h3 data-animation-percent="20">Come visit new parts of the world</h3> <p data-animation-percent="40"> Don't wait, there is a wide world out there that you can explore! Contact us to see what we can do </p> <div class="readmore" data-animation-percent="60">Find out more</div> </div>
Элементы видео будут содержать тег video со всеми его дочерними source настроенными на разные типы данных, для максимальной совместимости. Узнайте больше о добавлении поддержки нескольких форматов видео .
Элементы заголовка будут содержать всю разметку, которую вы хотите добавить в процессе воспроизведения видео. Вы можете добавить что угодно, но он должен иметь атрибут data-animation-percent со значением от 0 до 100 . Это скажет ползунку, на каком проценте завершения видео исчезать элемент.
Индикатор выполнения отображает текущий прогресс видео (как в секундах, так и в процентах). Это будет периодически обновляться. Бар будет интерактивным; Когда вы наводите курсор на него, видео приостанавливается, и вы сможете просматривать его, обновляя позицию видео.
Предоставление запасного варианта для мобильных браузеров
Чтобы помочь охватить все наши базы, мы также настроим запасной элемент, который будет использоваться в случае, если текущий браузер является мобильным устройством.
Добавьте следующую разметку непосредственно перед концом основного видеооболочки
<!--Fallback--> <div class="fallback-container"> <div class="image"></div> <div class="overlay"></div> <div class="caption"> <h1 data-animation-percent="15">This is a title</h1> <h3 data-animation-percent="25">Fallback when you dont support autoplay!</h3> <p data-animation-percent="50">Come and see a wide range of tasks and activities</p> <div class="readmore" data-animation-percent="70">Act now!</div> </div> </div>
Это будет работать аналогично нашим видео. Когда пользователь загрузит страницу, мы запустим все ее элементы заголовка, чтобы исчезнуть в зависимости от значения, установленного в атрибуте data-animation-percent . Вместо видео мы используем фоновое изображение.
Обнаружение мобильных браузеров
Наш слайдер будет использовать autoplay элемента video для автоматического воспроизведения первого видео. Однако большинство мобильных браузеров блокируют эту функциональность (чтобы ограничить использование данных), что означает, что наилучшей политикой является обнаружение, если мы находимся на мобильном устройстве, и отображение запасного контента соответствующим образом. Обычно мы делаем это с использованием функции обнаружения, однако обнаружение поддержки атрибута autoplay довольно сложно .
Каким бы уродливым ни был нюхающий браузер / UA, он даст нам возможность проверить текущий браузер на соответствие известному списку мобильных устройств и определить, как нам действовать дальше. Мы можем сделать это используя следующее регулярное выражение:
var mobile = navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile|IEMobile/i);
Который мы можем затем использовать так:
if(!mobile){ //main video slider functionality } else { //fallback functionality }
Текущая и следующая настройка видео
Примечание : для функциональности JavaScript я использую jQuery, поэтому возьмите себе копию и добавьте ее внизу страницы.
Когда мы довольны тем, что у нас нет мобильных устройств, мы ищем все наши элементы с помощью класса video-container и присваиваем коллекцию нашей переменной videos . Эти элементы будут основными обертками для каждого видео и содержания его подписи. Затем мы находим элемент video каждого контейнера и присваиваем его локальной переменной video .
Теперь, когда у нас есть текущее видео, нам нужно найти следующий элемент видео, чтобы мы могли запустить его, чтобы начать загрузку и воспроизвести его, когда закончится текущий.
Если у нас есть другой элемент video-container мы назначаем его переменной nextVideo . Если у нас нет другого элемента video-container мы возвращаемся к первому.
var videos = $('.video-container'); videos.each(function(index){ var video = $(this).find('video'), nextVideo; if(index !== (videos.length - 1)){ nextVideo = $(this).next('.video-container').find('video'); } else { nextVideo = videos.first().find('video'); } });
Вы можете добавить столько элементов video-container сколько захотите, и определить дополнительные видео и подписи. Слайдер найдет следующее видео и создаст цикл, который будет продолжаться бесконечно.
Начало воспроизведения видео для первого видео
Для нашего первого видео нам нужно настроить несколько вещей, чтобы мы могли все двигаться.
- Мы добавляем
activeкласс в.video-containerпервого видео (это.video-containerвидео с относительным позиционированием, чтобы оно отображалось) - Установите для атрибута
preloadвидео значениеautoчтобы браузер начал загружать видео. -
Вызовите метод
play()чтобы воспроизведение началось немедленно
//first video, preload and play if(index === 0){ video.parents('.video-container').addClass('active'); video[0].preload = 'auto'; video[0].play(); }
Вспомогательные переменные для видео
Для каждого видео мы должны установить несколько переменных, которые мы будем использовать позже в наших мероприятиях.
var caption = video.siblings('.caption'); var captionItems = caption.find('[data-animation-percent]'); var videoBar = video.siblings('.progress-bar'); var dragging = false; var nextLoaded = false;
-
captionявляется контейнером для всех анимированных элементов заголовка -
captionItemsсодержит каждый элемент, который будет анимирован во время воспроизведения -
videoBarотносится к индикатору выполнения каждого видео (используется позже во время наших событий для визуального обновления происходящего). -
draggingбудет использоваться, когда мы ищем / пропускаем видео, чтобы изменить его позицию воспроизведения -
nextLoadedбудет использоваться для того, чтобы мы знали, когда уже начали загружать следующее видео в конце текущего воспроизведения видео (не позволяет нам вызыватьload()несколько раз)
Событие timeUpdate
Поскольку наше видео воспроизводится, оно периодически вызывает событие timeupdate . Мы будем использовать это событие для некоторой обработки:
$(video).on('timeupdate', function(){ //processing to go in here });
В обратном вызове (анонимная функция, которую мы передаем методу on jQuery) мы хотим получить время текущего видео. Мы устанавливаем переменную videoTime , находя currentTime видео и деля его на продолжительность, умноженную на 100. Это позволит нам узнать в процентном отношении, насколько полно видео.
var videoTime = ((this.currentTime / this.duration) * 100);
Запуск анимации для элементов заголовка
Если текущее видео имеет элементы заголовка, нам нужно проверить текущее время видео, чтобы увидеть, должны ли мы сделать элементы активными или неактивными.
Внутри нашей функции мы добавляем следующее
$(video).on('timeupdate', function(){ var videoTime = ((this.currentTime / this.duration) * 100); if(captionItems.length > 0){ captionItems.each(function(){ var item = $(this); var animTime = parseInt(item.attr('data-animation-percent')); if(videoTime >= animTime){ item.addClass('active'); } else { item.removeClass('active'); } }); if(captionItems.filter('.active').length !== 0){ caption.addClass('active'); } else { caption.removeClass('active'); } if(videoTime >= 90){ caption.removeClass('active'); captionItems.each(function(){ $(this).removeClass('active'); }); } } });
Вот разбивка того, что мы делаем
- Если длина наших
captionItemsбольше0это означает, что у нас есть элементы, которые мы должны отслеживать.- Для каждого из
captionItemsнам нужно собрать значение, хранящееся в его атрибутеdata-animation-percentи присвоить егоanimTime(значение должно быть от0до100). - Если текущий
videoTimeбольше, чем наши элементыanimTimeтогда нам нужно сделать элемент активным, добавивactiveкласс.
- Для каждого из
- Мы также получаем коллекцию
captionItemsи используем метод .filter jQuery, чтобы проверить, есть ли у нас какие-либоactiveэлементы класса. Если мы это сделаем, мы хотим добавить активный класс в оболочку заголовка (переменнаяcaption). - Мы также проверяем, является ли текущий
videoTimeбольше90(что означает, что мы закончили на 90%). Если мы близки к завершению, мы просматриваем все подписи и удаляем ихactiveкласс, а также удаляем его изcaption
Загрузка следующего видео
В том же событии timeupdate мы также хотим проверить продолжительность нашего текущего видео и посмотреть, следует ли нам начинать загрузку следующего видео.
if(videoTime >= 70 && nextLoaded === false){ nextVideo.preload = 'auto'; nextVideo.load(); nextLoaded = true; }
Вы можете увидеть это в действии в готовой демоверсии — следующее видео должно появиться / загрузиться на вкладке сети вашей консоли примерно на 70% завершения текущего видео, давая ему несколько секунд до того, как конечное событие вызовет вызов его для воспроизведения ,
Обновление индикатора выполнения во время воспроизведения
Так как мы хотим, чтобы индикатор выполнения часто обновлялся, мы не можем поместить его в функцию timeupdate (поскольку браузер определяет, как вызывается offen). Вместо этого мы вызываем setInterval и присваиваем его нашей переменной videoInterval . Каждые 100 мс мы будем вызывать функцию updateProgressAuto и передавать текущее воспроизводимое видео.
setInterval(function(){ updateProgressAuto(video); }, 100);
Автоматическое обновление индикатора выполнения с помощью UpdateProgressAuto
Каждые 100 мсек индикатор прогресса должен будет обновляться. Мы используем эту функцию для этой цели.
function updateProgressAuto(video){ var videoBar = $(video).siblings('.progress-bar'); var videoPercent = ((video[0].currentTime / video[0].duration ) * 100); videoBar.find('.progress').css('width', videoPercent + '%'); videoBar.find('.progress-value').html(parseFloat(video[0].currentTime).toFixed(2) + ' : ' + parseFloat(video[0].duration).toFixed(2)); videoBar.find('.progress-time').html(parseInt(videoPercent) + '%'); }
Вот что происходит.
- Мы получаем элемент индикатора выполнения и
videoPercentвремя видео по егоdurationи умножая на 100. - Мы обновляем ширину индикатора выполнения, чтобы отразить
currentTimeпроцентах - Мы обновляем текущее время / продолжительность видео, чтобы точно знать, когда оно закончится.
- Мы обновляем процент, показанный на видео панели, с текущим процентом.
Событие OnEnded
Когда текущее видео заканчивается, оно вызывает событие onEnded . Именно здесь мы переключим активный класс на контейнер nextVideo а затем вызовем его функцию воспроизведения, чтобы начать воспроизведение.
video[0].onended = function() { nextVideo.parents('.video-container').addClass('active'); video.parents('.video-container').removeClass('active'); nextVideo[0].play(); };
Обновление воспроизведения видео вручную
В качестве дополнительной функции, слайдер также позволяет вам вручную просматривать видео, изменяя его текущее время воспроизведения при нажатии или перетаскивании (позволяя перематывать или перематывать видео).
Мы связываем несколько обработчиков событий с событиями click , mousedown , mouseup и mousemove для переменной videoBar . Цель этого состоит в том, чтобы перевести позицию щелчка / позицию перетаскивания мыши, чтобы обновить позицию видео.
//seeking with the video bar videoBar.on('click', function(e){ updateProgressManual((e.pageX - $(this).offset().left) , video); }); //mouse moving videoBar.on('mousedown',function(e) { dragging = true; updateProgressManual(e.pageX - $(this).offset().left, video); }); //mouse up (choose time to seek to) videoBar.on('mouseup',function(e) { dragging = false; updateProgressManual(e.pageX - $(this).offset().left, video); }); //mouse dragging (actively seeking) videoBar.on('mousemove',function(e) { if(dragging === true){ updateProgressManual(e.pageX - $(this).offset().left, video); } });
Все эти события вызывают функцию updateProgressManual , которая обновляет время воспроизведения видео. Значение, которое мы соберем, будет текущей позицией pageX минус текущее левое offset видеобара (что даст нам правильное положение на индикаторе выполнения)
Обновление воспроизведения вручную с помощью функции UpdateProgressManual
Эта функция вызывается, когда мы вручную ищем текущее видео. Его цель — получить позицию, на которую щелкнули, и преобразовать ее во время, к которому видео должно стремиться.
//Manually updates the video when we seek using the progress bar function updateProgressManual(progressBarPosition, video){ var videoBar = $(video).siblings('.progress-bar'); var videoPercentage = ((progressBarPosition / videoBar.outerWidth()) * 100); videoBar.find('.progress').css('width', videoPercentage + '%'); videoBar.find('.progress-value').html(parseFloat(video[0].currentTime).toFixed(2) + " : " + parseFloat(video[0].duration).toFixed(2)); videoBar.find('.progress-time').html(parseInt(videoPercentage) + '%'); video[0].currentTime = ((video[0].duration * videoPercentage) / 100); }
Вот разбивка того, что происходит
- Мы рассчитываем
videoPercentage, получая ток, переданный в позиции, и деля его наouterWidthвремени видеобара на 100. Это скажет нам, какой процент мы хотим искать. - Мы устанавливаем ширину элемента
progressвнутриvideoBarв процентах, к которым мы стремимся. - Мы также хотим обновить время визуального воспроизведения в баре. Это делается путем получения
currentTimeиdurationвидео - Наконец, мы устанавливаем значение
currentTimeдля видео, чтобы оно вызывало указанный период времени.
Дополнительная функциональность
У слайдера также есть несколько других функций, которые могут оказаться полезными.
Когда videoBar пересекается с нашей мышью, мы расширяем индикатор выполнения, чтобы было легче нажимать / перетаскивать (чтобы искать видео). Кроме того, мы также приостанавливаем видео и активируем наше наложение. Когда мышь удаляется, все возвращается назад, начиная воспроизведение и удаляя классы.
Мы также проверяем, перемещаете ли вы мышь на область caption и ее элементы. Если заголовок в настоящее время активен, он будет замедлять видео через свойство playbackRate (делая воспроизведение в два раза быстрее). Когда мы убираем мышь, видео возвращается к нормальной скорости.
//When hovering over progress bar, pause video and restyle videoBar.on('mouseover', function(){ $(this).siblings('.progress-overlay').addClass('active'); $(this).addClass('expanded'); video[0].pause(); }); //When not hovering, unpause video and restyle back to normal videoBar.on('mouseout', function(){ $(this).siblings('.progress-overlay').removeClass('active'); $(this).removeClass('expanded'); video[0].play(); }); //if we have caption elements, slow playback on hover if(captionItems.length !==0){ video.parents('.video-container').on('mouseover','.caption.active', function(){ video[0].playbackRate = 0.5; }); video.parents('.video-container').on('mouseout','.caption.active', function(){ video[0].playbackRate = 1; }); }
Наш мобильный только резервный контент
Если мы на мобильном устройстве, мы не будем показывать наши видео, вместо этого мы будем показывать запасной контент. Вы можете проверить это в демонстрационной версии, установив mobile переменную в значение true.
Большая часть функциональности похожа на то, как мы обрабатывали каждое видео. Мы ищем все его элементы и затем определяем, когда их нужно добавить.
var fallbackInterval = setInterval(function(){ currentTime = (parseInt(currentTime) + timeInterval); fallbackElements.each(function(){ var animationPercent = parseInt($(this).attr('data-animation-percent')); if((currentTime / animationDuration * 100) >= animationPercent){ $(this).addClass('active'); } else { $(this).removeClass('active'); } }); //if we have any caption elements faded in if(fallbackElements.filter('.active').length !== 0){ fallbackElements.parents('.caption').addClass('active'); } //if we have ended, finish if(currentTime >= animationDuration){ clearInterval(fallbackInterval); } }, timeInterval);
Давайте пройдемся по тому, что происходит
- Мы находим
fallbackиfallbackElementsи устанавливаемfallbackконтейнер для активации. - Мы устанавливаем
currentTimeв0что дает нам время начала. Затем мы устанавливаемanimationDurationна5000чтобы указать, что полная анимация займет 5 секунд. Наконец, мы устанавливаемtimeIntervalравным50что означает, что каждые 50 мс мы будем иметь обновление. - Мы создаем наш основной цикл с помощью функции
setInterval(присваивая его нашей переменнойfallbackInterval). Мы устанавливаем интервал для запуска каждые 50 мс. - Внутри основного интервала мы получаем новое текущее время (добавляя
timeIntervalк переменнойcurrentTime). - Мы проверяем каждый из элементов заголовка по отношению к проценту этого нового времени, чтобы увидеть, должны ли мы активировать этот элемент.
- Если наш
currentTimeбольше нашегоanimationDurationмыfallbackIntervalиспользуя clearInterval, чтобы завершить все.
демонстрация
И, наконец, вот демонстрация готовой витрины. Вы можете нажать на видео, чтобы переключить воспроизведение.
Где отсюда?
Теперь, когда вы видите, как Video API можно использовать для создания интересных элементов, вы можете взять пример кода из этого и расширить его, чтобы сделать его еще более удивительным.
Есть много вещей, которые вы могли бы сделать, чтобы улучшить это, вот некоторые из них:
- Создайте более привлекательную анимацию, которая применяется к элементам заголовка по мере их появления. Вы также можете создать несколько различных анимаций на случай, если вы захотите их различить.
- Подайте совершенно другой опыт, если вы находитесь на мобильном телефоне. Может быть, у вас может быть слайдер изображений или другой интерактивный контент.
- Вы можете попытаться предоставить несколько резервных контейнеров с их собственными изображениями и контентом, чтобы имитировать то, что делает видео слайдер.
- Используйте дополнительные события, методы и свойства из API, чтобы сделать слайдер еще лучше.
Если в итоге вы создадите что-то замечательное, не стесняйтесь поделиться им с нами, я хотел бы услышать ваше мнение в комментариях ниже.




