2025-11-27 09:28:46 +00:00
|
|
|
|
<template>
|
|
|
|
|
|
<!-- #ifdef H5 -->
|
2025-12-17 07:07:36 +00:00
|
|
|
|
<h5-hls-video v-if="video_player_show" :propSrc="video_src" propAutoplay :propMuted="muted" class="video-size" @hlsError="error" @ended="ended" @loadedmetadata="loadedmetadata" @autoPlaySuccess="auto_play_success" @autoPlayError="auto_play_error"></h5-hls-video>
|
2025-11-27 09:28:46 +00:00
|
|
|
|
<!-- #endif -->
|
|
|
|
|
|
<!-- #ifdef MP -->
|
2025-12-15 07:25:15 +00:00
|
|
|
|
<live-player :src="video_src" autoplay :muted="muted" class="video-size" @statechange="statechange" @error="error" />
|
2025-11-27 09:28:46 +00:00
|
|
|
|
<!-- #endif -->
|
|
|
|
|
|
<!-- #ifdef APP -->
|
2025-12-17 07:07:36 +00:00
|
|
|
|
<video v-if="video_player_show" :src="video_src" autoplay :is-video="true" :controls="false" :muted="muted" object-fit="contain" :style="{'width': windowWidth + 'px', 'height': windowHeight + 'px', 'background-color': 'transparent'}" @play="loadedmetadata" @error="error" @ended="ended"></video>
|
2025-11-27 09:28:46 +00:00
|
|
|
|
<!-- #endif -->
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
2025-11-28 06:09:09 +00:00
|
|
|
|
import H5HlsVideo from '@/pages/plugins/live/pull/components/h5-hls-video/h5-hls-video.vue';
|
2025-11-28 09:20:46 +00:00
|
|
|
|
import { isEmpty } from '@/common/js/common/common.js';
|
2025-12-05 09:31:05 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 直播拉流视频组件
|
|
|
|
|
|
* 支持H5、小程序和APP三种平台的视频播放
|
|
|
|
|
|
* 根据不同平台使用不同的播放器组件实现视频播放功能
|
|
|
|
|
|
*/
|
2025-11-27 09:28:46 +00:00
|
|
|
|
export default {
|
2025-11-28 06:09:09 +00:00
|
|
|
|
components: {
|
|
|
|
|
|
H5HlsVideo
|
|
|
|
|
|
},
|
2025-11-27 09:28:46 +00:00
|
|
|
|
props: {
|
2025-12-05 09:31:05 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* 视频源地址
|
|
|
|
|
|
* @type {String}
|
|
|
|
|
|
* @default 'http://live-pull-all.shopxo.vip/68f764013572f9240ca7ce6c/shopxo122.m3u8'
|
|
|
|
|
|
*/
|
2025-12-04 10:14:59 +00:00
|
|
|
|
propSrc:{
|
2025-11-27 09:28:46 +00:00
|
|
|
|
type: String,
|
|
|
|
|
|
default: 'http://live-pull-all.shopxo.vip/68f764013572f9240ca7ce6c/shopxo122.m3u8'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-12-15 07:25:15 +00:00
|
|
|
|
watch: {
|
|
|
|
|
|
propSrc: {
|
|
|
|
|
|
handler(newVal, oldVal) {
|
|
|
|
|
|
if (newVal != oldVal) {
|
|
|
|
|
|
this.video_src = newVal;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
immediate: true
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-11-27 09:28:46 +00:00
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
windowWidth: 0,
|
2025-12-01 06:25:30 +00:00
|
|
|
|
windowHeight: 0,
|
|
|
|
|
|
muted: false,
|
2025-12-15 08:33:12 +00:00
|
|
|
|
video_src: '',
|
|
|
|
|
|
video_player_show: true,
|
2025-12-19 02:42:44 +00:00
|
|
|
|
error_msg_count: 0,
|
2025-11-27 09:28:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
created() {
|
2025-12-05 09:31:05 +00:00
|
|
|
|
// 获取窗口信息,用于设置视频尺寸
|
2025-11-27 09:28:46 +00:00
|
|
|
|
const data = uni.getWindowInfo();
|
|
|
|
|
|
this.windowWidth = data.windowWidth;
|
|
|
|
|
|
this.windowHeight = data.windowHeight;
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
2025-12-15 07:25:15 +00:00
|
|
|
|
reload_video() {
|
|
|
|
|
|
// #ifndef MP
|
|
|
|
|
|
// 深拷贝视频源地址,避免直接修改原地址
|
2025-12-15 08:33:12 +00:00
|
|
|
|
let src = '';
|
|
|
|
|
|
if (!isEmpty(this.propSrc)) {
|
|
|
|
|
|
src = this.propSrc;
|
|
|
|
|
|
}
|
2025-12-15 07:25:15 +00:00
|
|
|
|
this.video_src = ''; // 清除原地址
|
2025-12-15 08:33:12 +00:00
|
|
|
|
this.video_player_show = false;
|
2025-12-15 07:25:15 +00:00
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
this.video_src = src; // 重新赋值
|
2025-12-15 08:33:12 +00:00
|
|
|
|
this.video_player_show = true;
|
2025-12-19 02:42:44 +00:00
|
|
|
|
this.error_msg_count = 0;
|
2025-12-15 07:25:15 +00:00
|
|
|
|
}, 100);
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
},
|
|
|
|
|
|
// 视频元数据加载完成处理函数, 不太准确,有的时候是直播的中间区域状态加载完了,但是视频还没有开始播放
|
|
|
|
|
|
loadedmetadata() {
|
|
|
|
|
|
this.$emit('loadedmetadata');
|
|
|
|
|
|
},
|
2025-12-05 09:31:05 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* 直播播放器状态变化处理函数(小程序平台)
|
|
|
|
|
|
* @param {Object} e - 状态变化事件对象
|
|
|
|
|
|
*/
|
2025-11-27 09:28:46 +00:00
|
|
|
|
statechange(e) {
|
|
|
|
|
|
console.log(e.detail.code);
|
|
|
|
|
|
},
|
2025-12-05 09:31:05 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 播放错误处理函数
|
|
|
|
|
|
* 根据不同平台处理播放错误,并在适当条件下触发ended事件
|
|
|
|
|
|
* @param {Object} e - 错误事件对象
|
|
|
|
|
|
*/
|
2025-11-27 09:28:46 +00:00
|
|
|
|
error(e) {
|
2025-12-15 08:33:12 +00:00
|
|
|
|
// 只有组件显示时才触发这个事件
|
|
|
|
|
|
if (this.video_player_show) {
|
|
|
|
|
|
// #ifdef H5
|
|
|
|
|
|
// 非初次加载错误的, 直播结束
|
|
|
|
|
|
if (e.type != 'otherError' || e.details != 'internalException') {
|
2025-12-19 02:42:44 +00:00
|
|
|
|
// 3次切片报错之后,认为直播结束
|
|
|
|
|
|
if (e.details == 'levelLoadError') {
|
|
|
|
|
|
this.error_msg_count++;
|
|
|
|
|
|
if (this.error_msg_count > 2) {
|
|
|
|
|
|
this.error_msg_count = 0;
|
|
|
|
|
|
this.$emit('ended');
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.$emit('ended');
|
|
|
|
|
|
}
|
2025-12-15 08:33:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
// #ifdef APP-NVUE
|
|
|
|
|
|
if (!isEmpty(e.type) && e.type == 'error') {
|
|
|
|
|
|
this.$emit('ended');
|
|
|
|
|
|
}
|
|
|
|
|
|
// #endif
|
|
|
|
|
|
console.log(e, 'error');
|
2025-11-28 10:19:51 +00:00
|
|
|
|
}
|
2025-11-27 09:28:46 +00:00
|
|
|
|
},
|
2025-12-05 09:31:05 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 视频播放结束处理函数
|
|
|
|
|
|
* 当视频播放完成时触发ended事件通知父组件
|
|
|
|
|
|
*/
|
2025-11-27 09:28:46 +00:00
|
|
|
|
// video app使用这种方式,判断直播是否结束
|
|
|
|
|
|
ended() {
|
2025-11-28 06:46:57 +00:00
|
|
|
|
this.$emit('ended');
|
2025-12-01 06:25:30 +00:00
|
|
|
|
},
|
2025-12-05 09:31:05 +00:00
|
|
|
|
|
2025-12-01 06:37:56 +00:00
|
|
|
|
//#ifdef H5
|
2025-12-05 09:31:05 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* H5平台自动播放成功处理函数
|
|
|
|
|
|
* 当静音自动播放成功时触发mutedAutoPlaySuccess事件
|
|
|
|
|
|
* @param {Boolean} e - 是否自动播放成功
|
|
|
|
|
|
*/
|
2025-12-01 06:37:56 +00:00
|
|
|
|
// 网页有的时候直接访问会报错,所以这里需要判断一下,如果报错则静音播放,静音播放成功添加提示,用户操作之后改为非静音播放
|
2025-12-01 06:25:30 +00:00
|
|
|
|
// 静音自动播放成功, 触发事件, 添加提示弹出框,用户操作之后改为非静音播放
|
|
|
|
|
|
auto_play_success(e) {
|
|
|
|
|
|
// 静音播放成功时,触发事件,提示用户需要修改点击修改播放状态
|
|
|
|
|
|
if (e) {
|
|
|
|
|
|
this.$emit('mutedAutoPlaySuccess');
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-12-05 09:31:05 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* H5平台自动播放失败处理函数
|
|
|
|
|
|
* 当自动播放失败时,设置为静音状态重新尝试播放
|
|
|
|
|
|
* @param {Boolean} e - 是否自动播放失败
|
|
|
|
|
|
*/
|
2025-12-01 06:25:30 +00:00
|
|
|
|
// 自动播放失败, 静音播放
|
|
|
|
|
|
auto_play_error(e) {
|
|
|
|
|
|
// 播放失败,并且是非静音状态,则静音播放尝试是否成功
|
|
|
|
|
|
if (!e) {
|
|
|
|
|
|
this.muted = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-12-05 09:31:05 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* H5平台静音状态切换函数
|
|
|
|
|
|
* 用户点击后取消静音状态
|
|
|
|
|
|
*/
|
2025-12-01 06:25:30 +00:00
|
|
|
|
// 静音提示点击
|
|
|
|
|
|
muted_tap() {
|
|
|
|
|
|
this.muted = false;
|
2025-11-27 09:28:46 +00:00
|
|
|
|
}
|
2025-12-01 06:37:56 +00:00
|
|
|
|
// #endif
|
2025-11-27 09:28:46 +00:00
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
2025-11-28 09:20:46 +00:00
|
|
|
|
<style lang="scss" scoped>
|
2025-11-27 09:28:46 +00:00
|
|
|
|
.video-size {
|
|
|
|
|
|
width: 100vw;
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
}
|
2025-11-28 10:19:51 +00:00
|
|
|
|
.video-bg {
|
|
|
|
|
|
background-image: linear-gradient(to bottom,#ba623c,#14766a);
|
|
|
|
|
|
}
|
2025-11-27 09:28:46 +00:00
|
|
|
|
</style>
|