在TypeScript中使用video.js

🎯 目的


🤴(客户、甲方爸爸、......)要在网页中播放视频📹。

视频文件后台同事已经分片处理好了,生成了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构建的,一些相关的配置🤹就不详细叙述了,直接上代码吧。

最基本的项目结构.png

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,看效果:

现代浏览器:

现代浏览器.gif

IE10不支持m3u8

IE10不支持m3u8.png

IE9脚本报错

IE9脚本报错.png
👦 升级代码,支持到IE9

思路:
针对这种情况,我们要做妥协让步,让IE10播放mp4文件,而不是m3u8文件,而IE9就直接用原生的videomp4文件,总之就是一个目的,能播放出视频就行了,就别管播放的是哪类文件,界面好不好看了,都是江湖儿女👽,不用拘泥于这些繁文缛节。

  1. 为了IE9,添加core-js库:
yarn add core-js
  1. 由于涉及到dom节点的操作,图省事儿,添加jquery库:
yarn add jquery
yarn add @types/jquery -D
  1. 删除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>
  1. 新添加判断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
    }
}
  1. 改造index.ts文件,引入jqueryIEVersion模块,为对应的浏览器添加适当的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);
}

如此这般之后,IE9IE10就都能播放了,如图所示:

ie9-原生video标签.gif
IE10-videojs.gif
👨 进化一小下:修改样式、汉化
  • 把播放按钮弄圆

新建一个和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;

...

然后,按钮就变样了:


图片.png
  • 汉化这个事儿比较头疼,我之前是直接在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>`);
...

效果如下:


图片.png

这是项目最终的结构图,只是为了说明问题,真实项目中可千万别这么分类,太乱:


图片.png

好了,就这些吧,头疼😲,得吃点🍖了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345