找回密码
 立即注册
首页 python Python-Web 查看内容
HTML5提供了用于在文档中嵌入富媒体的元素 — <video><audio>— 这些元素通过自带的API来控制视频或音频的播放,搜索等。本文将向你展示如何执行一些常见的任务,如创建自定义播放控件。


前提:
JavaScript基础(见JavaScript第一步创建JavaScript代码块JavaScript对象入门),Web API简介
目标:
学习如何通过浏览器API来控制视频和音频的播放。


HTML5视频和音频


<video><audio>元素允许我们把视频和音频嵌入到网页当中。就像我们在音频和视频内容文中展示的一样,一个典型的实现如下所示:
<video controls>
  <source src="rabbit320.mp4" type="video/mp4">
  <source src="rabbit320.webm" type="video/webm">
  <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p>
</video>
你可以点击上面的文章链接来查看相关HTML元素的所有特性;但在这篇文章中,主要目的是学习我们最感兴趣的controls属性,它会启用默认的播放设置。如果没有指定该属性,则播放器中不会显示相关控件。


至此,你可能会觉得这个属性作用不大,但是它确实很有优势。使用原生浏览器控件的一个很大的问题在于,它们在各个浏览器中都不相同— 对于跨浏览器的支持并不是很好!另一个问题是,在大多数浏览器中原生控件难以通过键盘来操作。


你可以通过隐藏本地控件(通过删除controls属性),然后使用HTML,CSS和JavaScript编写自己的代码来解决这两个问题。在下一节中,我们将看到如何通过一些可用的工具来实现。


HTMLMediaElement API


作为HTML5规范的一部分,HTMLMediaElementAPI提供允许你以编程方式来控制视频和音频播放的功能—例如HTMLMediaElement.play(), HTMLMediaElement.pause(),等。该接口对<audio><video>两个元素都是可用的,因为在这两个元素中要实现的功能几乎是相同的。让我们通过一个例子来一步步演示一些功能。


着手开始


探索HTML打开HTML index文件。你将看到一些功能;HTML由视频播放器和它的控件所控制:
<div class="player">
  <video controls>
    <source src="video/sintel-short.mp4" type="video/mp4">
    <source src="video/sintel-short.mp4" type="video/webm">
    <!-- fallback content here -->
  </video>
  <div class="controls">
    <button class="play" data-icon="P" aria-label="play pause toggle"></button>
    <button class="stop" data-icon="S" aria-label="stop"></button>
    <div class="timer">
      <div></div>
      <span aria-label="timer">00:00</span>
    </div>
    <button class="rwd" data-icon="B" aria-label="rewind"></button>
    <button class="fwd" data-icon="F" aria-label="fast forward"></button>
  </div>
</div>

  • 播放器被嵌入在<div>元素之中,所以如果有需要的话,可以把它作为一个单元整体来设置其样式。
  • <video>元素层包含两个<source>元素,这样可以根据浏览器来加载其所支持的视频格式。
  • 这些控制的HTML 大概是最有趣的:
    • 我们有四个<button> — play/pause, stop, rewind, and fast forward.
    • 每个<button> 都有一个class,一个data-icon 属性来决定在每个按钮上显示什么(在下一节讲述他是如何工作的),和一个aria-label属性为每一个按钮提供容易理解的描述,即使我们没有在tags内提供可读的标签。当用户关注这些元素时含有aria-label 属性的内容也会被讲述人读出来。
    • 有一个设定的计时器/进度条<div>用来记录已经播放的时长。为了展示效果,提供了两个记录的装置—一个<span>包含了分钟和秒,和一个额外的<div>用来创建一个垂直的随着时间增加而增长的进度条。完成版本看上去是这样的, 点击查看完成版本 .



探索CSS
现在打开CSS文件来查看里面的内容。例子中的CSS样式并不是很复杂,我们突出了最主要的一部分。首先注意.controls 的样式:
.controls {
  visibility: hidden;
  opacity: 0.5;
  width: 400px;
  border-radius: 10px;
  position: absolute;
  bottom: 20px;
  left: 50%;
  margin-left: -200px;
  background-color: black;
  box-shadow: 3px 3px 5px black;
  transition: 1s all;
  display: flex;
}

.player:hover .controls, player:focus .controls {
  opacity: 1;
}
  • 我们从设置为hidden的自定义控件visibility开始。稍后在我们的JavaScript中,我们将控件设置为visible,并且从<video> 元素中移除controls 属性。这是因为,如果JavaScript由于某种原因没有加载,用户依然可以使用原生的控件播放视频。
  • 默认情况下,我们将控件的opacity设置为0.5 opacity,这样当您尝试观看视频时,它们就不会分散注意力。只有当您将鼠标悬停/聚焦在播放器上时,控件才会完全不透明。
  • 我们使用Flexbox( display: flex)布置控制栏内的按钮,以简化操作。



接下来,让我们看看我们的按钮图标:
@font-face {
   font-family: 'HeydingsControlsRegular';
   src: url('fonts/heydings_controls-webfont.eot');
   src: url('fonts/heydings_controls-webfont.eot?#iefix') format('embedded-opentype'),
        url('fonts/heydings_controls-webfont.woff') format('woff'),
        url('fonts/heydings_controls-webfont.ttf') format('truetype');
   font-weight: normal;
   font-style: normal;
}

button:before {
  font-family: HeydingsControlsRegular;
  font-size: 20px;
  position: relative;
  content: attr(data-icon);
  color: #aaa;
  text-shadow: 1px 1px 0px black;
}
首先在CSS的最上方我们使用@font-face块来导入自定义Web字体。这是一种图标字体——字母表中的所有字符都是各种常用图标,你可以尝试在程序中调用。


接下来,我们使用这些内容来显示每个按钮上的图标:


  • 我们使用::before选择器在每个<button>元素之前显示内容。
  • 我们使用content属性将各情况下要显示的内容设置为data-icon属性的内容。例如在播放按钮的情况下,data-icon包含大写的“P”。
  • 我们使用font-family将自定义Web字体应用于我们的按钮上。在该字体中“P”对应的是“播放”图标,因此播放按钮上显示“播放”图标。



图标字体非常酷有很多原因——减少HTTP请求,因为您不需要将这些图标作为图像文件下载。同时具有出色的可扩展性,以及您可以使用文本属性来设置它们的样式——例如colortext-shadow


最后让我们来看看进度条的CSS:
.timer {
  line-height: 38px;
  font-size: 10px;
  font-family: monospace;
  text-shadow: 1px 1px 0px black;
  color: white;
  flex: 5;
  position: relative;
}

.timer div {
  position: absolute;
  background-color: rgba(255,255,255,0.2);
  left: 0;
  top: 0;
  width: 0;
  height: 38px;
  z-index: 2;
}

.timer span {
  position: absolute;
  z-index: 3;
  left: 19px;
}
  • 我们将外部.timer  <div>设为flex:5,这样它占据了控件栏的大部分宽度。我们还设置,这样我们就可以根据它的边界方便地定位元素,而不是元素的边界。position: relative<body>
  • 内部 <div>  position:absolute绝对定位于外部<div>的顶部。它的初始宽度为0,因此根本无法看到它。随着视频的播放,JavaScript将动态的增加其宽度。
  • <span>也绝对位于计时器/进度条timer栏的左侧附近。
  • 我们还对内部<div>和<span>定义适当数值的z-index,以便进度条显示在最上层,内部 <div>显示在下层。这样,我们确保我们可以看到所有信息——一个box不会遮挡另一个。



实现JavaScript


我们已经有了一个相当完整的HTML 和CSS 接口;现在我们只需要调通所有按钮以使控件正常工作。


在与index.html文件相同的目录下创建新的JavaScript文件。命名为custom-player.js


在此文件的顶部,插入以下代码:
var media = document.querySelector('video');
var controls = document.querySelector('.controls');

var play = document.querySelector('.play');
var stop = document.querySelector('.stop');
var rwd = document.querySelector('.rwd');
var fwd = document.querySelector('.fwd');

var timerWrapper = document.querySelector('.timer');
var timer = document.querySelector('.timer span');
var timerBar = document.querySelector('.timer div');
这里我们创建变量来保存对我们想要操作的所有对象的引用。有如下三组:


  • <video> 元素,和控制栏。
  • 播放/暂停,停止,快退,和快进按钮。
  • 进度条外面的<div>,数字计时器的<span>,以及内部的<div>会随着视频播放逐渐变宽。

接下来,在代码的底部插入以下内容:

media.removeAttribute('controls');
controls.style.visibility = 'visible';
这两行从视频中删除默认浏览器控件,并使自定义控件可见。


播放和暂停视频
让我们实现最重要的控件——播放/暂停按钮。

首先,在代码底部添加以下内容,以便在单击play按钮时调用playPauseMedia()函数:
play.addEventListener('click', playPauseMedia);

现在,要定义playPauseMedia()——在代码底部添加以下内容:
function playPauseMedia() {
  if(media.paused) {
    play.setAttribute('data-icon','u');
    media.play();
  } else {
    play.setAttribute('data-icon','P');
    media.pause();
  }
}

我们用ifstatement来检查视频是否暂停。HTMLMediaElement。暂停属性返回true如果媒体暂停,这是任何时候的视频不播放,包括当它是坐在0持续时间后,第一次加载。如果暂停,我们将play按钮上的data-iconattribute值设置为“u”,这是一个“暂停”图标,并调用HTMLMediaElement.play()方法来播放媒体。

在第二次单击时,按钮将再次被切换回——“play”图标将再次显示,视频将使用htmlmediaelement .pause()暂停。

停止视频
接下来,让我们添加处理停止视频的功能。在前面添加的代码下面添加以下addEventListener()行:
stop.addEventListener('click', stopMedia);
media.addEventListener('ended', stopMedia);

clickevent很明显——当单击stop按钮时,我们想通过运行stopMedia()函数来停止视频。不过,我们也想在视频结束时停止播放——这是由结束触发标记的,所以我们还设置了一个监听器来在事件触发时运行函数。

接下来,让我们定义stopMedia()——在playPauseMedia()下面添加以下函数:
function stopMedia() {
  media.pause();
  media.currentTime = 0;
  play.setAttribute('data-icon','P');
}

HTMLMediaElement API上没有stop()方法——等效的方法是暂停()视频,并将其currentTimeproperty设置为0。将currenttime设置为一个值(以秒为单位)立即将媒体跳转到该位置。

接下来要做的就是将显示的图标设置为“play”图标。无论视频是暂停还是在按下停止按钮时播放,您都希望它在播放后准备好播放。

反复寻找
有很多方法可以实现倒带和快进功能;在这里,我们向您展示了一种相对复杂的方法,它不会在按下不同按钮的顺序时中断。

首先,在前面的行下面添加以下两行addEventListener():
rwd.addEventListener('click', mediaBackward);
fwd.addEventListener('click', mediaForward);

下面是事件处理函数——在前面的函数下面添加以下代码来定义mediaBackward()和mediaForward():
var intervalFwd;
var intervalRwd;

function mediaBackward() {
  clearInterval(intervalFwd);
  fwd.classList.remove('active');

  if(rwd.classList.contains('active')) {
    rwd.classList.remove('active');
    clearInterval(intervalRwd);
    media.play();
  } else {
    rwd.classList.add('active');
    media.pause();
    intervalRwd = setInterval(windBackward, 200);
  }
}

function mediaForward() {
  clearInterval(intervalRwd);
  rwd.classList.remove('active');

  if(fwd.classList.contains('active')) {
    fwd.classList.remove('active');
    clearInterval(intervalFwd);
    media.play();
  } else {
    fwd.classList.add('active');
    media.pause();
    intervalFwd = setInterval(windForward, 200);
  }
}

您将注意到,首先我们初始化两个变量——intervalfwd&intervalrwd——稍后您将了解它们的用途。

我们来看mediaBackward()(mediaForward()的功能完全相同,但正好相反):

我们清除设置在快进功能上的任何类和间隔——我们这样做是因为如果我们在按下fwdbutton后按下rwdbutton,我们想取消任何快进功能,并将其替换为倒带功能。如果我们试图同时做这两件事,玩家就会崩溃。

我们使用ifstatement检查rwdbutton上是否设置了activeclass,表明它已经被按下了。classListis是一个非常方便的属性,存在于每个元素上——它包含元素上所有类的列表,以及添加/删除类的方法,等等。我们使用classList.contains()方法来检查列表是否包含activeclass。这将返回一个布尔值true/ falseresult。

如果在rwdbutton上设置了activehas,我们使用classList.remove()删除它,清除按钮第一次按下时设置的间隔(详见下文),并使用HTMLMediaElement.play()取消倒带并正常播放视频。

如果还没有设置,我们使用classList.add()将activeclass添加到rwdbutton,使用HTMLMediaElement.pause()暂停视频,然后设置intervalRwdvariable等于setInterval()调用。当调用setInterval()时,它创建一个活动的interval,这意味着它每x毫秒运行第一个参数给定的函数,其中x是第二个参数的值。在这里,我们每200毫秒运行一次windback()函数——我们将使用这个函数不断地向后播放视频。要停止一个setInterval()的运行,您必须调用clearInterval(),给它指定要清除的间隔的标识名,在本例中是变量名intervalRwd(请参阅函数前面的clearInterval()调用)。

最后,我们需要定义在setInterval()调用中调用的windreverse()和windForward()函数。在您之前的两个函数下面添加以下内容:
function windBackward() {
  if(media.currentTime <= 3) {
    rwd.classList.remove('active');
    clearInterval(intervalRwd);
    stopMedia();
  } else {
    media.currentTime -= 3;
  }
}

function windForward() {
  if(media.currentTime >= media.duration - 3) {
    fwd.classList.remove('active');
    clearInterval(intervalFwd);
    stopMedia();
  } else {
    media.currentTime += 3;
  }
}

再一次,我们只讲第一个函数因为它们的工作原理几乎是一样的,但它们是相反的。在windreverse()中,我们执行以下操作——记住,当间隔是活动的时,这个函数每200毫秒运行一次。

我们从一个ifstatement开始,它检查当前时间是否小于3秒,也就是说,如果再倒回3秒将使它回到视频的开始。这将导致奇怪的行为,因此如果是这种情况,我们将通过调用stopMedia()停止视频播放,从倒带按钮中删除activeclass,并清除intervalRwdinterval以停止倒带功能。如果我们不做最后一步,视频就会一直回放下去。

如果当前时间不在视频开始的3秒内,我们只需通过执行媒体从当前时间中删除3秒。currentTime - = 3。实际上,我们将视频重放3秒,每200毫秒重放一次。

更新经过的时间
我们的媒体播放器要实现的最后一个部分是经过的显示时间。为此,我们将运行一个函数来更新每次在元素上触发timeupdateevent时显示的时间。此事件触发的频率取决于您的浏览器、CPU能力等。

在其他行下面添加以下addEventListener()行:
media.addEventListener('timeupdate', setTime);

现在来定义setTime()函数。在文件底部添加以下内容:
function setTime() {
  var minutes = Math.floor(media.currentTime / 60);
  var seconds = Math.floor(media.currentTime - minutes * 60);
  var minuteValue;
  var secondValue;

  if (minutes < 10) {
    minuteValue = '0' + minutes;
  } else {
    minuteValue = minutes;
  }

  if (seconds < 10) {
    secondValue = '0' + seconds;
  } else {
    secondValue = seconds;
  }

  var mediaTime = minuteValue + ':' + secondValue;
  timer.textContent = mediaTime;

  var barLength = timerWrapper.clientWidth * (media.currentTime/media.duration);
  timerBar.style.width = barLength + 'px';
}

这是一个相当长的函数,让我们一步一步来看看:首先,我们计算HTMLMediaElement.currentTimevalue中的分钟和秒数。

然后我们初始化另外两个变量——minutevalue和secondValue。

这两个if语句计算出分钟和秒数是否小于10。如果是这样的话,他们会在数值上加上一个前导零,就像数字时钟显示一样。

显示的实际时间值设置为minuteValueplus一个冒号加上secondValue。

的节点。计时器的textContentvalue设置为时间值,因此它显示在UI中。

我们应该通过计算外部

的宽度(任何元素的clientWidthproperty都将包含它的长度),然后将其与HTMLMediaElement相乘来确定内部
的长度。currenttimediviby total HTMLMediaElement。观察图象媒体。
我们将内部

的宽度设置为等于计算出的bar长度加上“px”,因此它将被设置为像素的数量。

修复播放和暂停
还有一个问题需要解决。如果播放/暂停或停止按钮按下时,倒带或快进功能是活跃的,他们只是不工作。我们如何修复它,使他们取消rwd/ fwdbutton功能和播放/停止视频,如你所料?这很容易修复。

首先,在stopMedia()函数中添加以下几行—anywhere将执行以下操作:
rwd.classList.remove('active');
fwd.classList.remove('active');
clearInterval(intervalRwd);
clearInterval(intervalFwd);

现在在playPauseMedia()函数的最开始添加相同的行(就在if语句的开始之前)。

此时,您可以从windback()和windForward()函数中删除等效的行,因为该功能已经在stopMedia()函数中实现了。

注意:您还可以进一步提高代码的效率,方法是创建一个单独的函数来运行这些行,然后在任何需要的地方调用它,而不是在代码中多次重复这些行。但这个问题还是由你决定吧。

分享至 : QQ空间
收藏
您需要登录后才可以回帖 登录 | 立即注册