扎实基础系列 - H5播放器

做为HTML5中的一大亮点,video标签的出现取代了以往Flash的地位,成为了标准的视频播放方案。css

接下来咱们将一步一步挖掘video的全部功能。html

基础使用

<video>
  <source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4">
  <source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.webm" type="video/webm">
  <p>您的浏览器不支持HTML5播放器</p>
</video>
复制代码

video标签下面使用多个source标签连接视频源,浏览器选取第一个支持的视频格式进行播放,当浏览器不支持video播放功能时,会显示标签里的其余内容,提示用户采用其余方法观看。web

固然,仍是更简单是使用方法:浏览器

<video src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4">
  <p>您的浏览器不支持HTML5播放器</p>
</video>
复制代码

咱们获得下图,不知道的觉得咱们只加载了一张图片,由于它不会动:缓存

video_demo.jpg

经常使用属性

autoplay

咱们在video标签上添加autoplay属性让其加载后自动播放。bash

<video autoplay>...</video>
复制代码

好了,如今视频动起来了,它开始播放了!服务器

controls

可是问题又来了,把鼠标悬上去以后,发现啥也没发生,咱们控制不了视频的播放!markdown

咱们为video标签再加上controls属性,再来看看。数据结构

截屏20200324上午11.19.15.jpg

如今当你鼠标移上视频的时候,底部会出现一些控制功能,每一个浏览器都不同,可是通常会提供:播放/暂停、导航、全屏、音量功能。dom

loop

布尔属性,循环播放

muted

布尔属性,控制视频是否静音

preload

视频预加载设置。

  • none 不会请求视频任何信息
  • metadata 只请求视频的一些元信息
  • auto 视频须要下载

设置合适的值能够减小服务器的访问量。

poster

视频海报,须要是图片地址。 当视频在第一帧可用时,啥都不会展现,可是若是设置了poster,那么在用户播放或者跳帧前展现该图片做为封面。

<video poster="/example/image.jpg">...</video>
复制代码

可是咱们发现,poster的尺寸和视频并不匹配,会出现空白的地方,那咱们怎么去调整呢?使用css属性object-fit能够帮助咱们,经过设置合适的值能让咱们的poster撑满元素。

width,height

元素的宽高,通常不在这里设置。

DOM API

了解了video标签支持的属性以后,咱们能够将一个视频展示在用户面前,它能够自动播放,循环播放,静音播放,有首帧海报。可是,这些功能确定是不能知足咱们的不少需求的,而且浏览器提供的controls各有所异,咱们又怎么去实现一个跨浏览器的播放器呢?

还好咱们可使用JS去控制DOM来实现更多的媒体操做功能。

点击查看HTML Audio/Video具体支持的属性方法列表

接下来,咱们就要实现一个本身的视频播放器!

DIY

播放/暂停

咱们来实现的第一个功能,就是最基础的播放暂停。

须要使用到的API:

  • 方法:play()parse()
  • 属性:paused

咱们按照最开始的基础使用小节,先写一个video标签。一开始这个视频是没有控制器,而且不会自动播放的。

而后咱们开始使用JS配合DOM来定义一些视频播放控制器,先来定义一个Video

class Video {
  $video;
  constructor(options) {
    this.$video = document.querySelector(options.videoElement);
  }
}

复制代码

再定义播放/暂停方法:

play() {
  this.$video.play();
}
pause() {
  this.$video.pause();
}
复制代码

而后咱们将事件绑定在对应的元素上:

$playCtr.addEventListener("click", e => {
  if (this.$video.paused) {
    this.play();
    e.target.innerText = "暂停";
  } else {
    this.pause();
    e.target.innerText = "播放";
  }
});
复制代码

这里注意的是咱们判断视频的播放状态paused来切换播放状态。 这样咱们就有了一个能够切换的播放/暂停的功能。

进度条

接下来咱们实现一个实时反映视频播放进度的控制器,而且可以利用该控制器来跳转视频的播放时间,这里咱们使用最基础的控件input[type=range]

须要使用到的API:

  • 属性:durationcurrentTime

在确保视频元数据加载完毕后,咱们来初始化进度条的一些基础信息:

initProgress($progressCtr) {
  $progressCtr.value = 0;
  $progressCtr.min = 0;
  $progressCtr.max = this.$video.duration;
}
复制代码

而后监听播放时间变化来更新控件的值:

this.$video.addEventListener("timeupdate", e => {
  $progressCtr.value = e.target.currentTime;
});
复制代码

最后监听控件的值来切换视频播放点:

$progressCtr.addEventListener("change", e => {
  this.$video.currentTime = +e.target.value;
});
复制代码

这样咱们就实现了一个简单的进度条:

能够看出还有不少细节须要完善,但目前咱们不做讨论。

音量

其实音量控制和进度控制的思路是同样的,也是采用input[type=range]控件,这里咱们还须要控制静音状态。

须要使用到的API:

  • 属性:mutedvolume

咱们先初始化音量控件的最大最小值:

initVolume($volumeCtr) {
  $volumeCtr.value = this.$video.volume;
  $volumeCtr.step = 0.01;
  $volumeCtr.min = 0;
  $volumeCtr.max = 1;
}
复制代码

这里有些小细节,音量的最大值为1.0(100%),最小值为0。 因为默认step为1,因此咱们须要调节该值,使咱们能更精细地控制音量。

而后咱们再监听控件的值变化,去改变视频的音量:

$volumeCtr.addEventListener("change", e => {
  const volume = e.target.value;
  if (volume > 0) {
    this.$video.muted = false;
  }
  this.$video.volume = volume;
});
复制代码

播放速率

调节播放速率也是一个很常见的功能,慢速看细节,快速跳剧情,咱们来实现一个。也是使用input[type=range]控件。

须要使用到的API:

  • 属性:playbackRate
inityPlaybackRate($speedCtr) {
  $speedCtr.value = 1;
  $speedCtr.step = 0.25;
  $speedCtr.min = 1;
  $speedCtr.max = 2;
  $speedCtr.addEventListener("change", e => {
    this.$video.playbackRate = +e.target.value;
  });
}
复制代码

全屏

咱们来实现一个让视频全屏播放的功能。

须要使用到的API:

  • DOM:Element.requestFullscreen()

这个功能和video标签没有什么太大的联系,任何元素均可以全屏展现。该方法会返回一个Promise,并在完成全屏时resolve

initFullscreen($fullscreenCtr) {
  $fullscreenCtr.addEventListener("click", e => {
    this.$video.requestFullscreen();
  });
}
复制代码

这里咱们发现,在Chrome和Safari中,若是直接将video标签全屏,浏览器会自动将元素撑满屏幕,而且会加上controls。因此若是咱们要把本身的控制器也带上,就得在最外层再包装一层,而后全屏最外层元素。

另外全屏接口是有浏览器差别的,因此这里有个兼容方法:

function toFullVideo(videoDom) {
  if (videoDom.requestFullscreen) {
    return videoDom.requestFullscreen();
  } else if (videoDom.webkitRequestFullScreen) {
    return videoDom.webkitRequestFullScreen();
  } else if (videoDom.mozRequestFullScreen) {
    return videoDom.mozRequestFullScreen();
  } else {
    return videoDom.msRequestFullscreen();
  }
}
复制代码

用户体验优化

尽管咱们可以实现基础的视频控制,不过如今咱们的用户体验仍是不好的,好比视频缓存量显示、视频加载提示、错误提示、字幕等等,这些咱们都没有,不过好在咱们有一些想法去实现这些功能。

所须要使用到的API:

  • 属性:buffered
  • 事件:waitingerrorcanplayplaying...

缓冲提示

首先咱们来测试一些播放事件:

function log(e) {
  console.log(`${e.type}`);
}
this.$video.addEventListener("canplay", log);
this.$video.addEventListener("canplaythrough", log);
this.$video.addEventListener("play", log);
this.$video.addEventListener("playing", log);
this.$video.addEventListener("waiting", log);
this.$video.addEventListener("ended", log);
复制代码

在咱们播放一个正常视频时它是这样的:

play
playing
ended
复制代码

当视频有一些卡顿时是这样的:

play
playing
waiting
canplay
playing
waiting
...
复制代码

在这里咱们能够针对视频缓冲增长加载提示,也就是在waiting的时候加载提示(转圈圈),在canplay时去掉提示。

缓冲量展现

另外还有一个事件叫作progress,用它搭配上buffered,我们就能够清楚的知道视频的缓存加载了多少。

buffered返回的是一个TimeRanges对象,他有length属性标识有几个buffer区间,用户可能跳转视频,因此可能出现多个。还有俩方法获取buffer区间的起始位置,startend

// 第一个区间的起始位置
start(0)
// 第一个区间的结束位置
end(0)
复制代码

那么咱们能够获取到全部的buffer记录:

logBuffered() {
  this.$video.addEventListener("progress", e => {
    const { length } = this.$video.buffered;
    const buffers = [];
    for (let i = 0; i < length; i++) {
      const s = this.$video.buffered.start(i);
      const e = this.$video.buffered.end(i);
      buffers.push(`${s} - ${e}`);
    }
  });
}
复制代码

最后buffers的结果多是这样的:

["0 - 10", "20 - 40"]
复制代码

咱们这里只是展现其数据结构

考虑到progress的触发频率也能够作节流,而后渲染UI。

相关文章
相关标签/搜索