🎯 目的
🤴(客户、甲方爸爸、......)要在网页中播放视频📹。
视频文件后台同事已经分片处理好了,生成了m3u8
文件,同时分片前的原始视频(mp4
文件)也在服务器上保留了一份。
📚 理论部分
✨ 为什么使用video.js
首先,video.js使用得非常广泛,这就有了扎实的群众基础👨👩👦👦,由此衍生的是文档和实例也多啊,那学习(其实就是抄🤦)起来甚是方便👏。
其次,因为要播放m3u8
文件,但PC端浏览器并不支持video标签直接播放m3u8
格式的视频,video.js
安装了videojs-contrib-hls.js
插件后就可以播放了,而且7以后的版本已经支持这类文件了,不用再装此插件,用起来很方便。
最后,播放界面是统一的,看起来顺眼😍。
🎎 浏览器兼容性
项目要求最低IE9
,哎,这是个沉重而伤心的话题😭。
在实际操作中发现了这样情况(这些情况仅仅是个人总结,管中窥豹🐆、盲人摸象🐘,很片面):
-
IE9
不支持video.js
库,也不支持m3u8
格式,因此要使用原生的video标签加载原始视频。 -
IE10
支持video.js
库,但不支持m3u8
格式,因此要使用video.js
加载原始视频。 - 其他现代浏览器即支持
video.js
库,也支持m3u8
格式,因此要使用video.js
加载m3u8
文件,分片播放.ts
格式的视频。
🏹 实战部分
🔮 在项目中添加video.js
库和类型定义文件@types/video.js
yarn add video.js
yarn add @types/video.js -D
额外说明一下:还得引入core-js
库,因为不引用它的话,在IE9
浏览器下会报脚本错误(又是那个伤心的话题,再次流泪😭,为我因此而消耗的时间流泪💦)。如果不用兼容IE9
,可以不引用。
🔞 项目结构
由于项目是用webpack
构建的,一些相关的配置🤹就不详细叙述了,直接上代码吧。
package.json
代码:
{
"name": "webpack-ts-videojs",
"version": "0.0.0",
"description": "在TypeScript项目中使用video.js",
"scripts": {
"build": "webpack",
"start": "webpack-dev-server"
},
"author": "BigDipper",
"license": "MIT",
"dependencies": {
"video.js": "^7.8.2",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12"
},
"devDependencies": {
"@types/video.js": "^7.3.10",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.6.0",
"html-webpack-plugin": "^4.3.0",
"style-loader": "^1.2.1",
"ts-loader": "^7.0.5",
"typescript": "^3.9.5",
"webpack-dev-server": "^3.11.0"
}
}
webpack.config.js
代码:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: 'development', // 模式,默认两种 production和development
entry: './src/index.ts', // 入口,从哪个文件开始打包
output: { // 出口
filename: 'bundle.js', // 打包后的文件名
path: path.resolve(__dirname, './build') // 路径必须是一个绝对路径
},
devServer: { // 开发服务器的配置
port: 3000, //端口
progress: true, // 打包时显示进度条
compress: true, // 启用gzip压缩
proxy: { // 代理接口
'/apis': {
target: 'http://192.168.229.128:8080', // 后端联调地址
changeOrigin: true,
secure: false,
},
},
},
devtool: 'inline-source-map',
module: {
rules: [{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}, {
test: /\.css$/,
use: [
'style-loader', // 将 JS 字符串生成为 style 节点
'css-loader', // 将 CSS 转化成 CommonJS 模块
]
}]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
plugins: [ // 数组,放着所有的webpack插件
new CleanWebpackPlugin({
cleanAfterEveryBuildPatterns: ['build']
}),
new HtmlWebpackPlugin({
template: './src/index.html', // 指定要打包的模板
filename: 'index.html', // 打包后生成的文件
})
]
};
就这么多吧,代码太长了没心思看下去,而且这也不是重点。
👶 最基本的调用
在index.html
文件中,添加<video>
标签:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<video id="myVideo" class="video-js vjs-big-play-centered" preload="auto" poster='' data-setup='{}'></video>
</body>
</html>
在index.ts
中引用video.js
的库和样式,并调用:
import 'video.js/dist/video-js.css'
import videojs from 'video.js';
videojs(document.getElementById('myVideo'), {
autoplay: false,
controls: true,
sources: [{
src: '/apis/attachFiles/admin/2020/6/2016561465586925611.m3u8',
type: 'application/x-mpegURL'
}
]
});
之后,在命令行运行npm start
,看效果:
现代浏览器:
IE10不支持m3u8
IE9脚本报错
👦 升级代码,支持到IE9
思路:
针对这种情况,我们要做妥协让步,让IE10播放mp4
文件,而不是m3u8
文件,而IE9就直接用原生的video
播mp4
文件,总之就是一个目的,能播放出视频就行了,就别管播放的是哪类文件,界面好不好看了,都是江湖儿女👽,不用拘泥于这些繁文缛节。
- 为了
IE9
,添加core-js
库:
yarn add core-js
- 由于涉及到
dom
节点的操作,图省事儿,添加jquery
库:
yarn add jquery
yarn add @types/jquery -D
- 删除
index.html
中的<video>
标签,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
- 新添加判断IE版本的模块
IEVersion.ts
,文档位置与index.ts
平级,代码如下:
// 获取IE版本
export function IEVersion() {
// 取得浏览器的userAgent字符串
let userAgent = navigator.userAgent;
// 判断是否为小于IE11的浏览器
let isLessIE11 = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1;
// 判断是否为IE的Edge浏览器
let isEdge = userAgent.indexOf('Edge') > -1 && !isLessIE11;
// 判断是否为IE11浏览器
let isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;
if (isLessIE11) {
let IEReg = new RegExp('MSIE (\\d+\\.\\d+);');
// 正则表达式匹配浏览器的userAgent字符串中MSIE后的数字部分,,这一步不可省略!!!
IEReg.test(userAgent);
// 取正则表达式中第一个小括号里匹配到的值
let IEVersionNum = parseFloat(RegExp['$1']);
if (IEVersionNum === 7) {
// IE7
return 7
} else if (IEVersionNum === 8) {
// IE8
return 8
} else if (IEVersionNum === 9) {
// IE9
return 9
} else if (IEVersionNum === 10) {
// IE10
return 10
} else {
// IE版本<7
return 6
}
} else if (isEdge) {
// edge
return 'edge'
} else if (isIE11) {
// IE11
return 11
} else {
// 不是ie浏览器
return -1
}
}
- 改造
index.ts
文件,引入jquery
和IEVersion
模块,为对应的浏览器添加适当的dom
节点和播放视频,代码如下:
import 'core-js';
import $ from 'jquery';
import 'video.js/dist/video-js.css'
import videojs from 'video.js';
import { IEVersion } from './IEVersion';
let ieVersion = IEVersion();
let isIE9: boolean = ieVersion === 9;
let isIE10: boolean = ieVersion === 10;
if (isIE9) { // ie9播放视频 原生的video标签
$('body').append(`
<video id="myVideo" preload="auto" poster='' controls>
<source src="/apis/attachFiles/admin/2020/6/2016561465586925611.mp4" type="video/mp4">
</video>
`);
} else { // video.js播放
let options: {autoplay: boolean, controls: boolean, language: string, sources: any[]} = {
autoplay: false,
controls: true,
language: 'zh-CN',
sources: []
};
if (isIE10) { // ie10播放视频
options.sources.push({
src: '/apis/attachFiles/admin/2020/6/2016561465586925611.mp4',
type: 'video/mp4'
});
} else {
options.sources.push({
src: '/apis/attachFiles/admin/2020/6/2016561465586925611.m3u8',
type: 'application/x-mpegURL'
});
}
$('body').append(`<video id="myVideo" class="video-js vjs-big-play-centered" preload="auto" poster='' data-setup='{}'></video>`);
videojs(document.getElementById('myVideo'), options);
}
如此这般之后,IE9
和IE10
就都能播放了,如图所示:
👨 进化一小下:修改样式、汉化
- 把播放按钮弄圆
新建一个和index.ts
同级的样式文件index.css
,代码如下:
/* 播放按钮变圆形 */
.video-js .vjs-big-play-button{
font-size: 2.5em;
line-height: 2.3em;
height: 2.5em;
width: 2.5em;
-webkit-border-radius: 2.5em;
-moz-border-radius: 2.5em;
border-radius: 2.5em;
background-color: #73859f;
background-color: rgba(115,133,159,.5);
border-width: 0.15em;
margin-top: -1.25em;
margin-left: -1.75em;
}
/* 中间的播放箭头 */
.vjs-big-play-button .vjs-icon-placeholder {
font-size: 1.63em;
}
/* 加载圆圈 */
.vjs-loading-spinner {
font-size: 2.5em;
width: 2em;
height: 2em;
border-radius: 1em;
margin-top: -1em;
margin-left: -1.5em;
}
在index.ts
中引入此样式:
...
import { IEVersion } from './IEVersion';
import './index.css'
let ieVersion = IEVersion();
let isIE9: boolean = ieVersion === 9;
...
然后,按钮就变样了:
- 汉化这个事儿比较头疼,我之前是直接在
index.ts
文件中引入了video.js/dist/lang/zh-CN.js
文件,但是会报错,提示没有videojs
这个对象,所以现在就用了个简单粗暴的法子,将zh-CN.js
文件的内容拷贝到了index.ts
中,代码如下:
...
} else {
ptions.sources.push({
src: '/apis/attachFiles/admin/2020/6/2016561465586925611.m3u8',
type: 'application/x-mpegURL'
});
}
// 汉化设置
// 由于引入/node_modules/video.js/dist/lang/zh-CN.js会报错,因此将此文件内容复制过来了。
// 其实也用不了这么多汉化,但我真的是不想再摘出来了,累了。
videojs.addLanguage('zh-CN', {
"Play": "播放",
"Pause": "暂停",
"Current Time": "当前时间",
"Duration": "时长",
"Remaining Time": "剩余时间",
"Stream Type": "媒体流类型",
"LIVE": "直播",
"Loaded": "加载完成",
...
}
$('body').append(`<video id="myVideo" class="video-js vjs-big-play-centered" preload="auto" poster='' data-setup='{}'></video>`);
...
效果如下:
这是项目最终的结构图,只是为了说明问题,真实项目中可千万别这么分类,太乱:
好了,就这些吧,头疼😲,得吃点🍖了。