h5 视频解决方案 videojs

html5 video 标签在不同的浏览器里,解析有差异,所以使用 videojs 来处理兼容性问题

videojs 官网
videojs Github

1. 引入

1.1 全局引入

页面里全局引入 videojs 即可,js文件建议放在 body 底部位置

如果在 PC 端使用,还需要引入 videojs-flash.js(flash模式播放)、videojs-contrib-hls.js(解析流媒体 m3u8)

1
2
3
4
<link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
<script src="https://unpkg.com/video.js/dist/video.js"></script>
<script src="https://unpkg.com/videojs-flash/dist/videojs-flash.js"></script>
<script src="https://unpkg.com/videojs-contrib-hls/dist/videojs-contrib-hls.js"></script>

1.2 构建工具内局部引入

安装依赖

1
npm install video.js --save-dev
1
2
import videojs from 'video.js';
window.videojs = videojs || videojs.default;

注意 videojs-contrib-hls 依赖包并不支持 import 模块方式引入,所以想兼容 PC 时需要按上小节方式全局引入

2. 使用

以下场景为,正方形流媒体视频 m3u8 格式,点击开始,再次点击暂停

videojs初始化完毕后,.vjs-tech 为DOM结构里的实际的video标签

src 为父组件传过来的视频地址,poster 为视频未加载时显示的图片

videojs 的初始化参数有多重配置方式,建议以标签属性的方式来配置

2.1 标签属性的说明

注意 html 行内的属性,写了就生效了,controls="true"controls="false" 都是错误地写法,写完整必须写为controls="controls"

x5 开头的标签只对腾讯 x5 内核的浏览器有效,即微信、QQ浏览器,所有的属性见 H5同层播放器接入规范

显示控制条 controls
行内播放(不自动全屏播放)webkit-playsinline playsinline x5-playsinline

【安卓】启用H5同层播放器 x5-video-player-type=”h5”
启用后微信、QQ浏览器里,不会使用腾讯的默认播放器
这里如果不启用,则使用腾讯的播放器,videojs 控制不了,会显示播放控件
如果启用了,则使用 html5 默认行为来播放,videojs 可以控制,但一定会全屏播放

2.2 一般页面的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<video id="my-video" class="video-js vjs-default-skin only-play-button"
webkit-playsinline playsinline x5-playsinline controls
poster="https://testec.ghs.net/public/images/8d/69/0e/0bf26ca05396e726ad05540d582580bc322c20b9.jpg"
data-setup="{}" preload="auto"
>
<source src="http://cdn.ghs-tv.readtv.cn/video/ebeefe116c9aa4835e18b53b15a8cd26/stream.m3u8" type="application/x-mpegURL">
<!-- <source src="http://www.streambox.fr/playlists/test_001/stream.m3u8" type="application/x-mpegURL"/> -->
</video>
<button id="play-btn">播放</button>
<button id="pause-btn">暂停</button>

<script type="text/javascript">
var player = videojs(window.document.querySelector('#my-video'),{},function(){
let v = this.el_.querySelector('.vjs-tech');
v.removeAttribute('z-index');
// 当暂停时,点击开始播放
v.addEventListener('click', () => {
if (this.paused()) {
this.play();
}
});
// 当播放时,触摸暂停。注意这里只有 touchstart 有效,其他事件不能被触发
v.addEventListener('touchstart', () => {
if (!this.paused()) {
this.pause();
}
});
});

window.document.querySelector('#play-btn').addEventListener('click',function(){
player.play();
});
window.document.querySelector('#pause-btn').addEventListener('click',function(){
player.pause();
});
</script>

2.3 vuejs组件内的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<template>
<video id="my-video" class="video-js vjs-default-skin only-play-button"
controls webkit-playsinline playsinline style="object-fit:fill"
x5-playsinline
:poster="poster"
data-setup='{}'
>
<source :src="src" type="application/x-mpegURL"/>
</video>
</template>

<script>
import videojs from 'video.js';
window.videojs = videojs || videojs.default;

export default {
props: ['src', 'poster'],
mounted() {
if (!this.player) {
this.player = videojs(this.$el, {}, function playerReady() {
let v = this.el_.querySelector('.vjs-tech');
v.removeAttribute('z-index');
// 当暂停时,点击开始播放
v.addEventListener('click', () => {
if (this.paused()) {
this.play();
}
});
// 当播放时,触摸暂停。注意这里只有 touchstart 有效,其他事件不能被触发
v.addEventListener('touchstart', () => {
if (!this.paused()) {
this.pause();
}
});
});
}
},
beforeDestroy() {
if (this.player) {
this.player.dispose();
}
},
};
</script>

<style>
@import url('/static/css/video-js.min.css');
<style>

父组件中

1
<video-player :src="m3u8视频地址" :poster="视频预览图"></video-player>

3.样式优化

只在视频中央显示一个圆按钮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/* scss/less */
.video-js {
width: 100vw;
height: 100vw;
}

.only-play-button {
.vjs-big-play-button {
top: 50%;
left: 50%;
margin-top: -1.5em;
margin-left: -1.5em;
z-index: 10;
}

.vjs-icon-placeholder {
font-size: 2em;
}

&.vjs-paused .vjs-big-play-button {
display: block;
height: 3em;
line-height: 3em;
border-radius: 1.5em;
}

&.vjs-controls-disabled.vjs-paused .vjs-big-play-button,
&.vjs-using-native-controls.vjs-paused .vjs-big-play-button,
&.vjs-error.vjs-paused .vjs-big-play-button {
display: none;
}

.vjs-control-bar,
.vjs-error-display,
.vjs-text-track-display {
display: none;
}
}

4. 自动播放

只有 iOS 微信里,可以调用微信客户端的 JSBridge 方法,实现自动播放

1
2
3
document.addEventListener("WeixinJSBridgeReady", function (){
player.play();
}, false)

5. 部分浏览器兼容问题

360浏览器,它会自动给video标签加z-index值,导致点击不到videojs播放控件

解决方式:移除 video 标签的 style 属性,使 z-index 修正为正常。

1
2
3
$("video").on("play",function(){
$(this).attr("style","");
});

baidu浏览器,播放时loading图闪烁

解决方式:判断是百度浏览器时,不显示 loading 图

1
2
3
if(window.navigator && (window.navigator.userAgent).match(/baidu/i)) {
$(".vjs-loading-spinner").hide();
}