| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- <template>
- <div class="video-player-container">
- <video
- ref="videoElement"
- class="video-js vjs-default-skin vjs-big-play-centered"
-
- preload="auto"
- :poster="poster"
- >
- <source :src="src" :type="type">
- <!-- <track
- v-if="subtitle"
- kind="subtitles"
- :src="subtitle"
- srclang="zh-CN"
- label="中文"
- default
- > -->
- 您的浏览器不支持HTML5视频播放
- </video>
- </div>
- </template>
- <script setup>
- import { ref, onMounted, onUnmounted, watch } from 'vue'
- import videojs from 'video.js'
- import 'video.js/dist/video-js.css'
- // 组件属性
- const props = defineProps({
- // 视频地址
- src: {
- type: String,
- required: true
- },
- // 视频封面
- poster: {
- type: String,
- default: ''
- },
- // 视频类型
- type: {
- type: String,
- default: 'video/mp4'
- },
- // 是否自动播放
- autoplay: {
- type: Boolean,
- default: false
- },
- // 是否显示控件
- controls: {
- type: Boolean,
- default: true
- },
- // 是否自适应容器大小
- fluid: {
- type: Boolean,
- default: true
- },
- // 预加载方式
- preload: {
- type: String,
- default: 'auto'
- },
- // 字幕文件地址
- subtitle: {
- type: String,
- default: ''
- },
- // 播放速度选项
- playbackRates: {
- type: Array,
- default: () => [ 0.75, 1, 1.25, 1.5, 2]
- },
- // 自定义控件配置
- controlBar: {
- type: Object,
- default: () => ({
- // timeDivider: true,
- // durationDisplay: true,
- // remainingTimeDisplay: false,
- // fullscreenToggle: true,
- currentTimeDisplay:true,
- timeDivider:true,
- durationDisplay:true,
- remainingTimeDisplay:false,
- volumePanel: {
- inline: false,
- },
- children: [
- {name: 'playToggle'}, // 播放按钮
- {name: 'currentTimeDisplay'}, // 当前已播放时间
- {name: 'timeDivider'}, // 总时间
- {name: 'durationDisplay'}, // 总时间
- // {name: 'remainingTimeDisplay'}, // 剩余时间
- {name: 'progressControl'}, // 播放进度条
- {
- name: 'volumePanel', // 音量控制
- inline: false, // 不使用水平方式
- },
- {name: 'FullscreenToggle'}
- ]
- })
- },
- // 视频高度(可选,支持固定高度)
- height: {
- type: String,
- default: 'auto'
- }
- })
- // 组件事件
- const emit = defineEmits([
- 'play', // 播放事件
- 'pause', // 暂停事件
- 'ended', // 播放结束事件
- 'timeupdate', // 播放时间更新事件
- 'loadedmetadata',// 元数据加载完成事件
- 'error', // 错误事件
- 'ready' // 播放器就绪事件
- ])
- const videoElement = ref(null)
- let player = null
- // 初始化播放器
- onMounted(() => {
- initPlay();
- })
- // 监听src变化,更新视频源
- watch(() => props.src, (newSrc, oldSrc) => {
- console.log('newSrc', newSrc, 'oldSrc', oldSrc)
- if (player && newSrc !== oldSrc && newSrc !== '') {
- player.src({ src: newSrc, type: props.type })
- player.load()
- if (props.autoplay) {
- player.play()
- }
- }
- })
- // 监听poster变化,更新封面
- watch(() => props.poster, (newPoster) => {
- if (player) {
- player.poster(newPoster)
- }
- })
- const initPlay = ()=>{
- if (player) {
- player.dispose()
- player = null
- }
- // 创建video.js播放器实例
- player = videojs(videoElement.value, {
- autoplay: props.autoplay,
- controls: props.controls,
- fluid: props.fluid,
- preload: props.preload,
- aspectRatio: "16:9",
- // playbackRates: props.playbackRates,// 播放速度选项
- sources: [{ src: props.src, type: props.type }], // 添加这行
- controlBar: props.controlBar,
- })
- // 绑定事件
- player.on('play', () => emit('play'))
- player.on('pause', () => emit('pause'))
- player.on('ended', () => emit('ended'))
- player.on('timeupdate', () => emit('timeupdate', player.currentTime()))
- player.on('loadedmetadata', () => emit('loadedmetadata', player.duration()))
- player.on('error', () => emit('error', player.error()))
- player.on('ready', () => emit('ready', player))
- }
- // 组件销毁时清理播放器
- onUnmounted(() => {
- if (player) {
- player.dispose()
- player = null
- }
- })
- // 暴露方法给父组件
- defineExpose({
- // 播放
- play: () => player && player.play(),
- // 暂停
- pause: () => player && player.pause(),
- // 切换播放状态
- togglePlay: () => player && (player.paused() ? player.play() : player.pause()),
- // 跳转到指定时间
- seekTo: (time) => player && player.currentTime(time),
- // 获取当前播放时间
- getCurrentTime: () => player && player.currentTime(),
- // 获取视频总时长
- getDuration: () => player && player.duration(),
- // 判断是否正在播放
- isPlaying: () => player && !player.paused(),
- // 设置音量
- setVolume: (volume) => player && player.volume(volume),
- // 获取音量
- getVolume: () => player && player.volume(),
- // 设置播放速度
- setPlaybackRate: (rate) => player && player.playbackRate(rate),
- // 获取播放速度
- getPlaybackRate: () => player && player.playbackRate(),
- // 获取播放器实例(高级用法)
- getPlayerInstance: () => player,
- initPlay,
- });
- </script>
- <style scoped lang="scss">
- .video-player-container {
- width: 100%;
- border-radius: 8px;
- overflow: hidden;
-
- :deep(.video-js) {
- width: 100%;
- // height: 500px;
- border-radius: 8px;
- background-color: #000;
- // 自定义当前时间和总时间显示
- .vjs-current-time{
- display: block;
- }
- // 自定义总时间显示
- .vjs-duration{
- display: block;
- }
- // 自定义总时间和当前时间之间的分隔符
- .vjs-time-divider{
- display: block;
- }
-
- // 自定义大播放按钮样式
- .vjs-big-play-button {
- // width: 80px;
- // height: 80px;
- // line-height: 80px;
- // border-radius: 50%;
- // font-size: 30px;
- // border: none;
- // background-color: rgba(0, 0, 0, 0.6);
-
- // &:hover {
- // background-color: rgba(0, 0, 0, 0.8);
- // }
- }
-
- // 自定义控制栏样式
- .vjs-control-bar {
- // background: linear-gradient(to top, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0) 100%);
- // height: 60px;
- // padding: 0 10px;
- }
-
- // 自定义进度条样式
- .vjs-progress-control {
- // position: absolute;
- // top: 0;
- // left: 0;
- // width: 100%;
- // height: 5px;
- // margin: 0;
-
- // .vjs-progress-holder {
- // height: 100%;
-
- // .vjs-play-progress {
- // background-color: #409eff;
- // }
- // }
- }
- }
- }
- </style>
|