@videojs-player/vue 直播fiv 组件封装
包的版本
"@videojs-player/vue": "^1.0.0",
"flv.js": "1.6.2",
"video.js": "^8.22.0",
<template>
<!-- 封装的视频播放器组件 -->
<video-player ref="videRef" :options="state.playerOptions" :src="videoSrc" @mounted="handleMounted" @unmounted="handleUnmounted" />
</template>
<script setup lang="ts">
import { reactive, defineProps, defineEmits, getCurrentInstance, watch,ref } from "vue";
import { VideoPlayer } from '@videojs-player/vue'
import videojs from 'video.js'
import 'video.js/dist/video-js.css'
import video_zhCN from 'video.js/dist/lang/zh-CN.json'
import { FlvJsTech } from './flv-video-tech'
videojs.addLanguage('zh-CN', video_zhCN)
const { proxy } = getCurrentInstance();
// 注册 FlvJsTech
videojs.registerTech('Flvjs', FlvJsTech);
// 定义 props 类型
type Props = {
// 视频源地址
videoSrc: string;
// 是否显示控制栏
showControls: boolean;
// 是否自动播放
autoplay: boolean;
// 是否静音
muted: boolean;
// 是否循环播放
loop: boolean;
// 音量大小
volume: number;
// 是否禁用画中画
disablePictureInPicture: boolean;
// v-model 绑定的值,用于控制播放状态
modelValue: boolean;
};
// 定义 props
const props = defineProps<Props>();
/**
* 定义视频播放器可能触发的所有事件列表
* 这些事件将用于监听视频播放器的各种状态变化
* 例如加载开始、播放、暂停、结束等
*/
const eventsArr = [
// 视频开始加载时触发
'loadstart',
// 视频加载暂停时触发
'suspend',
// 视频加载中止时触发
'abort',
// 视频加载出错时触发
'error',
// 视频元素被清空时触发
'emptied',
// 视频加载停滞时触发
'stalled',
// 视频元数据加载完成时触发
'loadedmetadata',
// 视频的第一帧数据加载完成时触发
'loadeddata',
// 视频可以开始播放时触发
'canplay',
// 视频可以流畅播放时触发
'canplaythrough',
// 视频开始播放时触发
'playing',
// 视频暂停等待数据时触发
'waiting',
// 视频开始跳转时触发
'seeking',
// 视频跳转完成时触发
'seeked',
// 视频播放结束时触发
'ended',
// 视频时长发生变化时触发
'durationchange',
// 视频播放时间更新时触发
'timeupdate',
// 视频加载进度更新时触发
'progress',
// 视频开始播放时触发
'play',
// 视频暂停时触发
'pause',
// 视频播放速率改变时触发
'ratechange',
// 视频播放器尺寸改变时触发
'resize',
// 视频音量改变时触发
'volumechange',
// 视频海报改变时触发
'posterchange',
// 视频语言设置改变时触发
'languagechange',
// 视频全屏状态改变时触发
'fullscreenchange',
// 视频播放速率选项改变时触发
'playbackrateschange',
// 视频控制栏禁用时触发
'controlsdisabled',
// 视频控制栏启用时触发
'controlsenabled',
// 视频进入全屏窗口时触发
'enterFullWindow',
// 视频退出全屏窗口时触发
'exitFullWindow',
// 视频进入画中画模式时触发
'enterpictureinpicture',
// 视频离开画中画模式时触发
'leavepictureinpicture',
// 视频源设置完成时触发
'sourceset',
// 视频文本轨道改变时触发
'texttrackchange',
// 视频文本数据更新时触发
'textdata',
// 用户活动时触发
'useractive',
// 用户不活动时触发
'userinactive',
// 视频使用自定义控制栏时触发
'usingcustomcontrols',
// 视频使用原生控制栏时触发
'usingnativecontrols',
// 视频播放器销毁时触发
'dispose',
// 视频插件设置前触发
'beforepluginsetup',
// 视频插件设置完成时触发
'pluginsetup',
// 视频组件尺寸改变时触发
'componentresize',
// 视频播放器尺寸改变时触发
'playerresize',
// 视频播放器被点击时触发
'tap',
// 视频播放器准备好时触发
'ready'
];
// 定义事件
const emits = defineEmits();
type VideoJsPlayer = ReturnType<typeof videojs>;
const state = reactive({
playerOptions: {
// 是否显示控制栏,从 props 获取
controls: props.showControls,
// 是否等浏览器准备好后自动播放,从 props 获取
autoplay: props.autoplay,
// 是否静音,从 props 获取
muted: props.muted,
// 结束后是否重新开始,从 props 获取
loop: props.loop,
// 播放视频源,从 props 获取
// sources: [{ type: 'video/flv', src: props.videoSrc }],
// 为 true 时,播放器具有流畅的大小
fluid: true,
// 播放顺序
techOrder: [ 'flvjs','html5'],
// 音量,从 props 获取
volume: props.volume,
language: 'zh-CN',
// 禁用画中画,从 props 获取
disablePictureInPicture: props.disablePictureInPicture
}
});
const handleMounted = ({ player }: { player: VideoJsPlayer }) => {
// 设置视频源
// 触发自定义事件,将 player 对象传递给父组件
emits('update:playerReady', player);
eventsArr.forEach(event => {
player.on(event, (e) => {
let parameter = {
event: e,
theNameOfTheEvent: event,
videoJsPlayer: player,
}
emits('update:' + event, parameter);
});
});
// 监听播放和暂停事件,更新 v-model 绑定的值
player.on('play', () => {
emits('update:modelValue', true);
});
player.on('pause', () => {
emits('update:modelValue', false);
});
// 根据 v-model 绑定的值控制播放状态
if (props.modelValue) {
player.play();
} else {
player.pause();
}
};
const handleUnmounted = () => {
};
</script>
<style lang="scss" scoped>
/* 组件样式 */
</style>
flv-video-tech.ts 文件
// 引入 flv.js 库,用于处理 FLV 视频流
import flvjs from 'flv.js'
// 引入 Video.js 库,用于创建视频播放器
import videojs from 'video.js'
/**
* 获取 Video.js 的 Html5 技术类实例
* @type {any}
*/
const Html5 = videojs.getTech('Html5')! as any
/**
* 自定义的 FlvJsTech 类,继承自 Video.js 的 Html5 技术类
* 用于支持 FLV 视频的播放
*/
export class FlvJsTech extends Html5 {
private flvPlayer: flvjs.Player | null = null;
constructor(options: any, ready: any) {
super(options, ready);
this.flvPlayer = null;
}
/**
* 设置视频源
* @param {string} src - 视频源的 URL
*/
setSrc(src: string) {
this.dispose(); // 销毁之前的播放器
// 创建新的 flvPlayer 实例
this.flvPlayer = flvjs.createPlayer({ url: src, type: 'flv' }, this.options_);
// 确保播放器和媒体元素正确绑定
if (this.el_ && this.flvPlayer) {
this.flvPlayer.attachMediaElement(this.el_);
this.flvPlayer.load();
// 确保播放器加载完成后再开始播放
this.flvPlayer.on(flvjs.Events.LOADING_COMPLETE, () => {
if (this.flvPlayer) {
this.flvPlayer.play();
}
});
this.flvEvent(); // 绑定事件
} else {
console.error('Media element or flvPlayer is not ready');
}
}
// flvjs播放器事件侦听
flvEvent() {
if (this.flvPlayer) {
// 错误信息回调
this.flvPlayer.on(flvjs.Events.ERROR, (errorType: any, errorDetail: any, errorInfo: any) => {
// console.error('FLV Player Error:', errorType, errorDetail, errorInfo);
});
// 播放统计信息回调
this.flvPlayer.on(flvjs.Events.STATISTICS_INFO, (errorType: any, errorDetail: any, errorInfo: any) => {
// console.log('FLV Player Statistics:', errorType, errorDetail, errorInfo);
});
}
}
/**
* 销毁实例并清理资源
*/
dispose() {
// 销毁 flvPlayer 实例
if (this.flvPlayer) {
this.flvPlayer.pause();
this.flvPlayer.unload();
this.flvPlayer.detachMediaElement();
this.flvPlayer.destroy();
this.flvPlayer = null;
}
}
/**
* 支持的视频格式
* @type {{ 'video/flv': string; 'video/x-flv': string }}
*/
static formats = {
'video/flv': 'FLV',
'video/x-flv': 'FLV',
};
/**
* 检查当前环境是否支持 FLV 视频播放
* @returns {boolean} - 如果支持则返回 true,否则返回 false
*/
static isSupported = function () {
return flvjs.isSupported();
};
/**
* 检查指定的视频类型是否可以播放
* @param {string} type - 视频类型
* @returns {string} - 如果支持则返回 'maybe',否则返回空字符串
*/
static canPlayType = function (type: string) {
return FlvJsTech.isSupported() && type in FlvJsTech.formats ? 'maybe' : '';
};
/**
* 检查指定的视频源是否可以播放
* @param {any} source - 视频源对象
* @returns {string} - 如果支持则返回 'maybe',否则返回空字符串
*/
static canPlaySource = function (source: any) {
return FlvJsTech.isSupported() && source.src.endsWith('.flv') ? 'maybe' : '';
};
}
使用方式
<VideoPlayerWrapper v-model="state.isPlaying" :videoSrc="state.videoSrc" :showControls="true"
:autoplay="true" :muted="true" :loop="false" :volume="0.6" :disablePictureInPicture="true"
@update:usingnativecontrols="onTap" />
import VideoPlayerWrapper from '@/components/VideoPlayerWrapper/index.vue'