本文是由Tom Greco和Marc Towler进行同行评审的。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!

由于对本机视频元素及其API的支持相当全面 ,因此现在是一个绝佳时机,您可以研究可以利用视频为用户创建精美且互动的方式的方法。

在整篇文章中,我们将研究API的基础知识,在掌握了相关知识之后,我们将研究一个实际示例。 这将是一个多视频滑块,其中一个接一个地播放视频,并在播放时无缝地加载内容并设置动画效果。

视频API –简介

本质上,当我们谈论视频API时,实际上是在谈论媒体API —一种JavaScript API,它使您可以与网页上的音频和视频元素进行交互。

该API实现了一个称为HTMLMediaElement的接口,该接口添加了支持音频和视频常用的基本操作(例如加载媒体,更改查找位置,完成播放等)所需的属性 , 方法和事件 。 HTMLVideoElement和HTMLAudioElement都对其进行了扩展,它们提供了自己的特殊属性和方法。

我们主要关注video元素,因此我们将专注于与API此部分的交互。 要感受一下API,您可以访问Interactive HTML5 Video Example页面,其中展示了最常用的元素。

ios浏览器控制台 ipad safari控制台_移动开发

浏览器支持

虽然Chrome,Firefox,Safari,Opera和Internet Explorer都支持视频元素,但是它们可以播放的格式有所不同,每个浏览器都有其支持的视频格式列表,这些列表也可能基于浏览器本身的版本。

在撰写本文时,所有现代台式机和移动浏览器都将播放mp4格式。 另外,大多数浏览器将长期支持ogg或webm格式(或同时支持这两种格式)。 这是当前支持状态的综合概述 。

虽然仅提供mp4版本就可以解决问题,但您可能应该同时包含ogg和webm格式作为全面的解决方案。

互动视频展示

我们将使用video元素创建展示功能。 我们的展示柜将连续播放一系列小型视频片段,并在特定时间触发动画。 使用这样的视频元素,我们将研究其某些属性,方法和事件,并显示使用此API可以实现的控制级别。

ios浏览器控制台 ipad safari控制台_ios浏览器控制台_02

像往常一样,您可以在我们的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元素将包含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属性中设置的值。 我们使用的是背景图片,而不是视频。

检测移动浏览器

我们的滑块将使用video元素的autoplay属性自动播放第一个视频。 但是,大多数移动浏览器会阻止此功能(以限制数据使用),这意味着最好的策略是检测我们是否在移动设备上,并相应显示备用内容。 通常,我们将使用功能检测来执行此操作,但是, 检测对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分配给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中(此视频具有相对位置的样式,以便显示它)
  • 将视频的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
});

在回调(我们将传递给jQuery的on方法的匿名函数)中,我们想要获取当前视频的时间。 我们通过找到视频的currentTime并将其除以持续时间乘以100来设置videoTime变量。这将使我们知道视频的完整程度。

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集合,并使用jQuery的.filter方法检查我们是否有任何active类项目。 如果这样做,我们想将活动类添加到字幕包装器( caption变量)。
  • 我们还会检查当前的videoTime是否大于90 (这意味着我们完成了90%)。 如果我们快要结束了,我们将遍历所有标题并删除其active类,并将其从caption删除

加载下一个视频

在同一个timeupdate事件中,我们还想检查当前视频的时长,看看是否应该开始加载下一个视频。

if(videoTime >= 70 && nextLoaded === false){
  nextVideo.preload = 'auto';
  nextVideo.load();
  nextLoaded = true;
}

您可以在完成的演示中看到它的运行情况-下一个视频应该在当前视频的大约70%完成时出现/加载到控制台的“网络”标签中,并在结束事件触发触发播放前几秒钟。

ios浏览器控制台 ipad safari控制台_javascript_03

播放期间更新进度条

由于我们希望进度条经常更新,因此我们不能将其放在timeupdate函数中(因为浏览器确定了它的调用方式)。 相反,我们调用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) + '%');
}

这是怎么回事。

  • 我们正在获取进度条元素,并通过将视频的currentTime乘以其duration并乘以100来找到videoPercent 。
  • 我们更新进度条的宽度以反映currentTime百分比
  • 我们会更新视频的当前时间/时长,以便确切知道视频何时结束。
  • 我们用当前百分比更新视频栏上显示的百分比

即将结束的事件

当前视频结束时,将触发onEnded事件。 在这里,我们将活动类切换到nextVideo的容器,然后调用其play功能以开始播放

video[0].onended = function() {     
   nextVideo.parents('.video-container').addClass('active');
   video.parents('.video-container').removeClass('active');
   nextVideo[0].play(); 
};

手动更新视频的播放

作为一项附加功能,滑块还允许您手动浏览视频,并在单击或拖动时更改其当前播放时间(让您快退或快进视频)。

我们将多个事件处理程序绑定到videoBar变量的click , mousedown , mouseup和mousemove事件。 目的是转换鼠标的点击位置/拖动位置以更新视频的位置。

ios浏览器控制台 ipad safari控制台_移动开发_04

//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。这将告诉我们,我们要寻求什么样的百分比。
  • 我们将videoBar内的progress元素的宽度设置为我们要寻找的百分比。
  • 我们还希望更新栏中的视觉播放时间。 通过获取视频的currentTime和时duration
  • 最后,我们设置视频的currentTime值以使视频在指定的时间段内搜索。

附加功能

滑块还具有一些其他有用的功能。

当videoBar与我们的鼠标相交时,我们将展开进度条,以使其更易于单击/拖动(以查找视频)。 此外,我们还暂停了视频并激活了叠加层。 当鼠标移开时,所有内容都会还原,开始播放并删除类。

我们还将检查您是否将鼠标移到caption区域及其元素上。 如果字幕当前处于活动状态,它将通过playbackRate属性减慢视频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来在演示中对此进行测试。

大多数功能类似于我们处理每个视频的方式。 我们寻找其所有元素,然后确定何时需要淡入。

ios浏览器控制台 ipad safari控制台_javascript_05

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变量)。 我们将间隔设置为每50ms运行一次。
  • 在主间隔内,我们获得新的当前时间(通过将timeInterval添加到currentTime变量中)。
  • 我们对照此新时间的百分比检查每个标题元素,以查看是否应激活此元素。
  • 如果currentTime大于animationDuration ,则使用clearInterval清除fallbackInterval以完成所有操作。

演示版

最后,这是完成展示的演示。 您可以单击视频以切换播放。

请参阅CodePen上的SitePoint ( @SitePoint )提供的Pen Video API交互式展示 。

从这里到哪里?

现在,您已经了解了如何使用Video API创建有趣的元素,您可以从中获取示例代码并将其扩展以使其更加出色。

您可以做很多事情来改善这一点,其中一些是:

  • 创建一个更精美的动画,在字幕元素淡入时将其应用到字幕元素。您还可以创建多个不同的动画,以防它们有所区别。
  • 如果您使用手机,则可以提供完全不同的体验。 也许您可以具有图像滑块或其他一些交互式内容。
  • 您可以尝试为多个备用容器提供自己的图像和内容,以模仿视频滑块的功能。
  • 使用API中的其他事件,方法和属性可以使滑块更好。

如果您最终想与我们分享一些很棒的东西,在下面的评论中,我很乐意听取您的意见。