修改直播结束后的效果
parent
f0d125e6e0
commit
4944cd41d3
|
|
@ -1,147 +1,137 @@
|
|||
<!-- eslint-disable -->
|
||||
<template>
|
||||
<view class="player-wrapper" :id="videoWrapperId" :randomNum="randomNum"
|
||||
:change:randomNum="hlsVideoPlayer.randomNumChange" :viewportProps="viewportProps"
|
||||
:change:viewportProps="hlsVideoPlayer.viewportChange" :videoSrc="videoSrc"
|
||||
:change:videoSrc="hlsVideoPlayer.initVideoPlayer" :command="eventCommand"
|
||||
:change:command="hlsVideoPlayer.triggerCommand" :func="renderFunc" :change:func="hlsVideoPlayer.triggerFunc" />
|
||||
<view class="player-wrapper" :id="videoWrapperId" :randomNum="randomNum" :change:randomNum="hlsVideoPlayer.randomNumChange" :viewportProps="viewportProps" :change:viewportProps="hlsVideoPlayer.viewportChange" :videoSrc="videoSrc" :change:videoSrc="hlsVideoPlayer.initVideoPlayer" :command="eventCommand" :change:command="hlsVideoPlayer.triggerCommand" :func="renderFunc" :change:func="hlsVideoPlayer.triggerFunc" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
src: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
autoplay: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
controls: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
objectFit: {
|
||||
type: String,
|
||||
default: 'cover'
|
||||
},
|
||||
muted: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
playbackRate: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
poster: {
|
||||
type: String,
|
||||
default: ''
|
||||
export default {
|
||||
props: {
|
||||
src: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
autoplay: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
controls: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
objectFit: {
|
||||
type: String,
|
||||
default: 'cover'
|
||||
},
|
||||
muted: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
playbackRate: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
poster: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
randomNum: Math.floor(Math.random() * 100000000),
|
||||
videoSrc: '',
|
||||
// 父组件向子组件传递的事件指令(video的原生事件)
|
||||
eventCommand: null,
|
||||
// 父组件传递过来的,对 renderjs 层的函数执行(对视频控制的自定义事件)
|
||||
renderFunc: {
|
||||
name: null,
|
||||
params: null
|
||||
},
|
||||
// 提供给父组件进行获取的视频属性
|
||||
currentTime: 0,
|
||||
duration: 0,
|
||||
playing: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听视频资源地址更新
|
||||
src: {
|
||||
handler(val) {
|
||||
if (!val) return
|
||||
setTimeout(() => {
|
||||
this.videoSrc = val
|
||||
}, 0)
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
videoWrapperId() {
|
||||
return `video-wrapper-${this.randomNum}`
|
||||
},
|
||||
// 聚合视图层的所有数据变化,传给renderjs的渲染层
|
||||
viewportProps() {
|
||||
return {
|
||||
autoplay: this.autoplay,
|
||||
muted: this.muted,
|
||||
controls: this.controls,
|
||||
objectFit: this.objectFit,
|
||||
poster: this.poster,
|
||||
playbackRate: this.playbackRate
|
||||
}
|
||||
}
|
||||
},
|
||||
// 方法
|
||||
methods: {
|
||||
// 传递事件指令给父组件
|
||||
eventEmit({ event, data }) {
|
||||
this.$emit(event, data)
|
||||
},
|
||||
// 修改view视图层的data数据
|
||||
setViewData({ key, value }) {
|
||||
key && this.$set(this, key, value)
|
||||
},
|
||||
// 重置事件指令
|
||||
resetEventCommand() {
|
||||
this.eventCommand = null
|
||||
},
|
||||
// 播放指令
|
||||
play() {
|
||||
this.eventCommand = 'play'
|
||||
},
|
||||
// 暂停指令
|
||||
pause() {
|
||||
this.eventCommand = 'pause'
|
||||
},
|
||||
// 重置自定义函数指令
|
||||
resetFunc() {
|
||||
this.renderFunc = {
|
||||
name: null,
|
||||
params: null
|
||||
}
|
||||
},
|
||||
// 自定义事件 - 移除视频
|
||||
remove(params) {
|
||||
this.renderFunc = {
|
||||
name: 'removeHandler',
|
||||
params
|
||||
}
|
||||
},
|
||||
// 自定义事件 - 全屏
|
||||
fullScreen(params) {
|
||||
this.renderFunc = {
|
||||
name: 'fullScreenHandler',
|
||||
params
|
||||
}
|
||||
},
|
||||
// 跳转到指定时间点
|
||||
toSeek(time) {
|
||||
this.renderFunc = {
|
||||
name: 'toSeekHandler',
|
||||
params: time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
randomNum: Math.floor(Math.random() * 100000000),
|
||||
videoSrc: '',
|
||||
// 父组件向子组件传递的事件指令(video的原生事件)
|
||||
eventCommand: null,
|
||||
// 父组件传递过来的,对 renderjs 层的函数执行(对视频控制的自定义事件)
|
||||
renderFunc: {
|
||||
name: null,
|
||||
params: null
|
||||
},
|
||||
// 提供给父组件进行获取的视频属性
|
||||
currentTime: 0,
|
||||
duration: 0,
|
||||
playing: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听视频资源地址更新
|
||||
src: {
|
||||
handler(val) {
|
||||
if (!val) return
|
||||
setTimeout(() => {
|
||||
this.videoSrc = val
|
||||
}, 0)
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
videoWrapperId() {
|
||||
return `video-wrapper-${this.randomNum}`
|
||||
},
|
||||
// 聚合视图层的所有数据变化,传给renderjs的渲染层
|
||||
viewportProps() {
|
||||
return {
|
||||
autoplay: this.autoplay,
|
||||
muted: this.muted,
|
||||
controls: this.controls,
|
||||
objectFit: this.objectFit,
|
||||
poster: this.poster,
|
||||
playbackRate: this.playbackRate
|
||||
}
|
||||
}
|
||||
},
|
||||
// 方法
|
||||
methods: {
|
||||
// 传递事件指令给父组件
|
||||
eventEmit({
|
||||
event,
|
||||
data
|
||||
}) {
|
||||
this.$emit(event, data)
|
||||
},
|
||||
// 修改view视图层的data数据
|
||||
setViewData({
|
||||
key,
|
||||
value
|
||||
}) {
|
||||
key && this.$set(this, key, value)
|
||||
},
|
||||
// 重置事件指令
|
||||
resetEventCommand() {
|
||||
this.eventCommand = null
|
||||
},
|
||||
// 播放指令
|
||||
play() {
|
||||
this.eventCommand = 'play'
|
||||
},
|
||||
// 暂停指令
|
||||
pause() {
|
||||
this.eventCommand = 'pause'
|
||||
},
|
||||
// 重置自定义函数指令
|
||||
resetFunc() {
|
||||
this.renderFunc = {
|
||||
name: null,
|
||||
params: null
|
||||
}
|
||||
},
|
||||
// 自定义事件 - 移除视频
|
||||
remove(params) {
|
||||
this.renderFunc = {
|
||||
name: 'removeHandler',
|
||||
params
|
||||
}
|
||||
},
|
||||
// 自定义事件 - 全屏
|
||||
fullScreen(params) {
|
||||
this.renderFunc = {
|
||||
name: 'fullScreenHandler',
|
||||
params
|
||||
}
|
||||
},
|
||||
// 跳转到指定时间点
|
||||
toSeek(time) {
|
||||
this.renderFunc = {
|
||||
name: 'toSeekHandler',
|
||||
params: time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script module="hlsVideoPlayer" lang="renderjs">
|
||||
|
|
@ -180,14 +170,7 @@ export default {
|
|||
this.videoEl = videoEl
|
||||
// 开始监听视频相关事件
|
||||
this.listenVideoEvent()
|
||||
const {
|
||||
autoplay,
|
||||
muted,
|
||||
controls,
|
||||
playbackRate,
|
||||
objectFit,
|
||||
poster
|
||||
} = this.renderProps
|
||||
const { autoplay, muted, controls, playbackRate, objectFit, poster } = this.renderProps
|
||||
videoEl.autoplay = autoplay
|
||||
videoEl.controls = controls
|
||||
videoEl.muted = muted
|
||||
|
|
@ -230,244 +213,236 @@ export default {
|
|||
},
|
||||
// 播放视频流
|
||||
initHlsPlayer(src) {
|
||||
if (hlsjs.isSupported()) {
|
||||
this.hlsPlayer = new hlsjs()
|
||||
this.hlsPlayer.loadSource(src)
|
||||
this.hlsPlayer.attachMedia(this.videoEl)
|
||||
this.hlsPlayer.on(hlsjs.Events.MANIFEST_PARSED, () => {
|
||||
// hls 视频流加载完成
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'hlsManifestParsed'
|
||||
})
|
||||
if (hlsjs.isSupported()) {
|
||||
this.hlsPlayer = new hlsjs()
|
||||
this.hlsPlayer.loadSource(src)
|
||||
this.hlsPlayer.attachMedia(this.videoEl)
|
||||
this.hlsPlayer.on(hlsjs.Events.MANIFEST_PARSED, () => {
|
||||
// hls 视频流加载完成
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'hlsManifestParsed'
|
||||
})
|
||||
this.hlsPlayer.on(hlsjs.Events.ERROR, (event, data) => {
|
||||
})
|
||||
this.hlsPlayer.on(hlsjs.Events.ERROR, (event, data) => {
|
||||
console.error('HLS Error:', data)
|
||||
// 如果HLS播放失败,尝试直接播放源地址作为降级方案
|
||||
if (this.videoEl && data.fatal) {
|
||||
this.videoEl.src = src
|
||||
} else {
|
||||
// hls 视频加载错误
|
||||
console.error('HLS Error:', event, data)
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'hlsError',
|
||||
data
|
||||
})
|
||||
// 如果HLS播放失败,尝试直接播放源地址作为降级方案
|
||||
if (this.videoEl && data.fatal) {
|
||||
this.videoEl.src = src
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 浏览器不支持hls.js,直接使用原生播放
|
||||
this.videoEl.src = src
|
||||
}
|
||||
},
|
||||
// 监听视频相关事件
|
||||
listenVideoEvent() {
|
||||
// 播放事件监听
|
||||
const playHandler = () => {
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'play'
|
||||
})
|
||||
this.$ownerInstance.callMethod('setViewData', {
|
||||
key: 'playing',
|
||||
value: true
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('play', playHandler)
|
||||
this.videoEl.addEventListener('play', playHandler)
|
||||
// 暂停事件监听
|
||||
const pauseHandler = () => {
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'pause'
|
||||
})
|
||||
this.$ownerInstance.callMethod('setViewData', {
|
||||
key: 'playing',
|
||||
value: false
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('pause', pauseHandler)
|
||||
this.videoEl.addEventListener('pause', pauseHandler)
|
||||
// 结束事件监听
|
||||
const endedHandler = () => {
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'ended'
|
||||
})
|
||||
this.$ownerInstance.callMethod('resetEventCommand')
|
||||
}
|
||||
this.videoEl.removeEventListener('ended', endedHandler)
|
||||
this.videoEl.addEventListener('ended', endedHandler)
|
||||
// 加载完成事件监听
|
||||
const canPlayHandler = () => {
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'canplay'
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('canplay', canPlayHandler)
|
||||
this.videoEl.addEventListener('canplay', canPlayHandler)
|
||||
// 加载失败事件监听
|
||||
const errorHandler = (e) => {
|
||||
console.error('Video element error:', e)
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'error',
|
||||
data: e
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('error', errorHandler)
|
||||
this.videoEl.addEventListener('error', errorHandler)
|
||||
// loadedmetadata 事件监听
|
||||
const loadedMetadataHandler = () => {
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'loadedmetadata'
|
||||
})
|
||||
// 获取视频的长度
|
||||
const duration = this.videoEl.duration
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'durationchange',
|
||||
data: duration
|
||||
})
|
||||
this.$ownerInstance.callMethod('setViewData', {
|
||||
key: 'duration',
|
||||
value: duration
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('loadedmetadata', loadedMetadataHandler)
|
||||
this.videoEl.addEventListener('loadedmetadata', loadedMetadataHandler)
|
||||
// 播放进度监听
|
||||
const timeupdateHandler = (e) => {
|
||||
const currentTime = e.target.currentTime
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'timeupdate',
|
||||
data: currentTime
|
||||
})
|
||||
this.$ownerInstance.callMethod('setViewData', {
|
||||
key: 'currentTime',
|
||||
value: currentTime
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('timeupdate', timeupdateHandler)
|
||||
this.videoEl.addEventListener('timeupdate', timeupdateHandler)
|
||||
// 倍速播放监听
|
||||
const ratechangeHandler = (e) => {
|
||||
const playbackRate = e.target.playbackRate
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'ratechange',
|
||||
data: playbackRate
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('ratechange', ratechangeHandler)
|
||||
this.videoEl.addEventListener('ratechange', ratechangeHandler)
|
||||
// 全屏事件监听
|
||||
if (this.isApple()) {
|
||||
const webkitbeginfullscreenHandler = () => {
|
||||
const presentationMode = this.videoEl.webkitPresentationMode
|
||||
let isFullScreen = null
|
||||
if (presentationMode === 'fullscreen') {
|
||||
isFullScreen = true
|
||||
} else {
|
||||
isFullScreen = false
|
||||
}
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'fullscreenchange',
|
||||
data: isFullScreen
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('webkitpresentationmodechanged', webkitbeginfullscreenHandler)
|
||||
this.videoEl.addEventListener('webkitpresentationmodechanged', webkitbeginfullscreenHandler)
|
||||
} else {
|
||||
const fullscreenchangeHandler = () => {
|
||||
let isFullScreen = null
|
||||
if (document.fullscreenElement) {
|
||||
isFullScreen = true
|
||||
} else {
|
||||
isFullScreen = false
|
||||
}
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'fullscreenchange',
|
||||
data: isFullScreen
|
||||
})
|
||||
}
|
||||
document.removeEventListener('fullscreenchange', fullscreenchangeHandler)
|
||||
document.addEventListener('fullscreenchange', fullscreenchangeHandler)
|
||||
}
|
||||
},
|
||||
// 销毁播放器实例
|
||||
destroyPlayer() {
|
||||
if (this.hlsPlayer) {
|
||||
this.hlsPlayer.destroy()
|
||||
this.hlsPlayer = null
|
||||
}
|
||||
if (this.videoEl) {
|
||||
this.videoEl.pause()
|
||||
this.videoEl.src = ''
|
||||
// 移除所有事件监听器
|
||||
this.videoEl.removeAttribute('src')
|
||||
this.videoEl.load()
|
||||
this.videoEl = null
|
||||
}
|
||||
},
|
||||
triggerCommand(eventType) {
|
||||
if (eventType) {
|
||||
this.$ownerInstance.callMethod('resetEventCommand')
|
||||
if (this.videoEl) {
|
||||
try {
|
||||
this.videoEl[eventType]()
|
||||
} catch (e) {
|
||||
console.error(`Error executing ${eventType}:`, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
triggerFunc(func) {
|
||||
const {
|
||||
name,
|
||||
params
|
||||
} = func || {}
|
||||
if (name) {
|
||||
if (typeof this[name] === 'function') {
|
||||
this[name](params)
|
||||
}
|
||||
this.$ownerInstance.callMethod('resetFunc')
|
||||
}
|
||||
},
|
||||
removeHandler() {
|
||||
this.destroyPlayer()
|
||||
this.$ownerInstance.callMethod('setViewData', {
|
||||
key: 'videoSrc',
|
||||
value: ''
|
||||
})
|
||||
},
|
||||
fullScreenHandler() {
|
||||
if (this.videoEl) {
|
||||
if (this.isApple()) {
|
||||
if (this.videoEl.webkitEnterFullscreen) {
|
||||
this.videoEl.webkitEnterFullscreen()
|
||||
}
|
||||
} else {
|
||||
// 浏览器不支持hls.js,直接使用原生播放
|
||||
this.videoEl.src = src
|
||||
}
|
||||
},
|
||||
// 监听视频相关事件
|
||||
listenVideoEvent() {
|
||||
// 播放事件监听
|
||||
const playHandler = () => {
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'play'
|
||||
})
|
||||
this.$ownerInstance.callMethod('setViewData', {
|
||||
key: 'playing',
|
||||
value: true
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('play', playHandler)
|
||||
this.videoEl.addEventListener('play', playHandler)
|
||||
// 暂停事件监听
|
||||
const pauseHandler = () => {
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'pause'
|
||||
})
|
||||
this.$ownerInstance.callMethod('setViewData', {
|
||||
key: 'playing',
|
||||
value: false
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('pause', pauseHandler)
|
||||
this.videoEl.addEventListener('pause', pauseHandler)
|
||||
// 结束事件监听
|
||||
const endedHandler = () => {
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'ended'
|
||||
})
|
||||
this.$ownerInstance.callMethod('resetEventCommand')
|
||||
}
|
||||
this.videoEl.removeEventListener('ended', endedHandler)
|
||||
this.videoEl.addEventListener('ended', endedHandler)
|
||||
// 加载完成事件监听
|
||||
const canPlayHandler = () => {
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'canplay'
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('canplay', canPlayHandler)
|
||||
this.videoEl.addEventListener('canplay', canPlayHandler)
|
||||
// 加载失败事件监听
|
||||
const errorHandler = (e) => {
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'error',
|
||||
data: e
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('error', errorHandler)
|
||||
this.videoEl.addEventListener('error', errorHandler)
|
||||
// loadedmetadata 事件监听
|
||||
const loadedMetadataHandler = () => {
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'loadedmetadata'
|
||||
})
|
||||
// 获取视频的长度
|
||||
const duration = this.videoEl.duration
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'durationchange',
|
||||
data: duration
|
||||
})
|
||||
this.$ownerInstance.callMethod('setViewData', {
|
||||
key: 'duration',
|
||||
value: duration
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('loadedmetadata', loadedMetadataHandler)
|
||||
this.videoEl.addEventListener('loadedmetadata', loadedMetadataHandler)
|
||||
// 播放进度监听
|
||||
const timeupdateHandler = (e) => {
|
||||
const currentTime = e.target.currentTime
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'timeupdate',
|
||||
data: currentTime
|
||||
})
|
||||
this.$ownerInstance.callMethod('setViewData', {
|
||||
key: 'currentTime',
|
||||
value: currentTime
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('timeupdate', timeupdateHandler)
|
||||
this.videoEl.addEventListener('timeupdate', timeupdateHandler)
|
||||
// 倍速播放监听
|
||||
const ratechangeHandler = (e) => {
|
||||
const playbackRate = e.target.playbackRate
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'ratechange',
|
||||
data: playbackRate
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('ratechange', ratechangeHandler)
|
||||
this.videoEl.addEventListener('ratechange', ratechangeHandler)
|
||||
// 全屏事件监听
|
||||
if (this.isApple()) {
|
||||
const webkitbeginfullscreenHandler = () => {
|
||||
const presentationMode = this.videoEl.webkitPresentationMode
|
||||
let isFullScreen = null
|
||||
if (presentationMode === 'fullscreen') {
|
||||
isFullScreen = true
|
||||
} else {
|
||||
if (this.videoEl.requestFullscreen) {
|
||||
this.videoEl.requestFullscreen()
|
||||
}
|
||||
isFullScreen = false
|
||||
}
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'fullscreenchange',
|
||||
data: isFullScreen
|
||||
})
|
||||
}
|
||||
this.videoEl.removeEventListener('webkitpresentationmodechanged', webkitbeginfullscreenHandler)
|
||||
this.videoEl.addEventListener('webkitpresentationmodechanged', webkitbeginfullscreenHandler)
|
||||
} else {
|
||||
const fullscreenchangeHandler = () => {
|
||||
let isFullScreen = null
|
||||
if (document.fullscreenElement) {
|
||||
isFullScreen = true
|
||||
} else {
|
||||
isFullScreen = false
|
||||
}
|
||||
this.$ownerInstance.callMethod('eventEmit', {
|
||||
event: 'fullscreenchange',
|
||||
data: isFullScreen
|
||||
})
|
||||
}
|
||||
document.removeEventListener('fullscreenchange', fullscreenchangeHandler)
|
||||
document.addEventListener('fullscreenchange', fullscreenchangeHandler)
|
||||
}
|
||||
},
|
||||
// 销毁播放器实例
|
||||
destroyPlayer() {
|
||||
if (this.hlsPlayer) {
|
||||
this.hlsPlayer.destroy()
|
||||
this.hlsPlayer = null
|
||||
}
|
||||
if (this.videoEl) {
|
||||
this.videoEl.pause()
|
||||
this.videoEl.src = ''
|
||||
// 移除所有事件监听器
|
||||
this.videoEl.removeAttribute('src')
|
||||
this.videoEl.load()
|
||||
this.videoEl = null
|
||||
}
|
||||
},
|
||||
triggerCommand(eventType) {
|
||||
if (eventType) {
|
||||
this.$ownerInstance.callMethod('resetEventCommand')
|
||||
if (this.videoEl) {
|
||||
try {
|
||||
this.videoEl[eventType]()
|
||||
} catch (e) {
|
||||
console.error(`Error executing ${eventType}:`, e)
|
||||
}
|
||||
}
|
||||
},
|
||||
toSeekHandler(time) {
|
||||
if (this.videoEl) {
|
||||
this.videoEl.currentTime = time
|
||||
}
|
||||
},
|
||||
viewportChange(props) {
|
||||
this.renderProps = props
|
||||
const {
|
||||
autoplay,
|
||||
muted,
|
||||
controls,
|
||||
playbackRate
|
||||
} = props
|
||||
if (this.videoEl) {
|
||||
this.videoEl.autoplay = autoplay
|
||||
this.videoEl.controls = controls
|
||||
this.videoEl.muted = muted
|
||||
this.videoEl.playbackRate = playbackRate
|
||||
}
|
||||
},
|
||||
randomNumChange(val) {
|
||||
this.num = val
|
||||
}
|
||||
},
|
||||
triggerFunc(func) {
|
||||
const { name, params } = func || {}
|
||||
if (name) {
|
||||
if (typeof this[name] === 'function') {
|
||||
this[name](params)
|
||||
}
|
||||
this.$ownerInstance.callMethod('resetFunc')
|
||||
}
|
||||
},
|
||||
removeHandler() {
|
||||
this.destroyPlayer()
|
||||
this.$ownerInstance.callMethod('setViewData', {
|
||||
key: 'videoSrc',
|
||||
value: ''
|
||||
})
|
||||
},
|
||||
fullScreenHandler() {
|
||||
if (this.videoEl) {
|
||||
if (this.isApple()) {
|
||||
if (this.videoEl.webkitEnterFullscreen) {
|
||||
this.videoEl.webkitEnterFullscreen()
|
||||
}
|
||||
} else {
|
||||
if (this.videoEl.requestFullscreen) {
|
||||
this.videoEl.requestFullscreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
toSeekHandler(time) {
|
||||
if (this.videoEl) {
|
||||
this.videoEl.currentTime = time
|
||||
}
|
||||
},
|
||||
viewportChange(props) {
|
||||
this.renderProps = props
|
||||
const { autoplay, muted, controls, playbackRate } = props
|
||||
if (this.videoEl) {
|
||||
this.videoEl.autoplay = autoplay
|
||||
this.videoEl.controls = controls
|
||||
this.videoEl.muted = muted
|
||||
this.videoEl.playbackRate = playbackRate
|
||||
}
|
||||
},
|
||||
randomNumChange(val) {
|
||||
this.num = val
|
||||
}
|
||||
},
|
||||
// 组件销毁时清理资源
|
||||
beforeDestroy() {
|
||||
|
|
@ -476,10 +451,10 @@ export default {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.player-wrapper {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
<style lang="scss" scoped>
|
||||
.player-wrapper {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -88,7 +88,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
/* #ifndef APP-NVUE */
|
||||
@import url('@/static/icon/iconfont.css');
|
||||
/* #ifndef MP-WEIXIN */
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.a-img {
|
||||
position: fixed;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -616,7 +616,7 @@
|
|||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
<style lang="scss" scoped>
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
/* #ifndef APP-NVUE */
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
<template>
|
||||
<!-- #ifdef H5 -->
|
||||
<h5-hls-video :src="src" autoplay class="video-size" :muted="true"></h5-hls-video>
|
||||
<h5-hls-video :src="src" autoplay class="video-size" :muted="true" @hlsError="error" @ended="ended"></h5-hls-video>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP -->
|
||||
<live-player :src="src" autoplay :muted="true" class="video-size" @statechange="statechange" @error="error" />
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP -->
|
||||
<video :src="src" autoplay :is-video="true" :controls="false" muted object-fit="fill" :style="{width: windowWidth + 'px', height: windowHeight + 'px'}" @error="error" @ended="ended"></video>
|
||||
<video :src="src" autoplay :is-video="true" :controls="false" muted object-fit="contain" :style="{width: windowWidth + 'px', height: windowHeight + 'px'}" @error="error" @ended="ended"></video>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import H5HlsVideo from '@/pages/plugins/live/pull/components/h5-hls-video/h5-hls-video.vue';
|
||||
import { isEmpty } from '@/common/js/common/common.js';
|
||||
export default {
|
||||
components: {
|
||||
H5HlsVideo
|
||||
|
|
@ -41,17 +42,24 @@
|
|||
console.log(e.detail.code);
|
||||
},
|
||||
error(e) {
|
||||
console.log(e.detail.errMsg, 'error');
|
||||
// #ifdef H5
|
||||
// 非初次加载错误的, 直播结束
|
||||
if (e.type != 'otherError' || e.details != 'internalException') {
|
||||
this.$emit('ended');
|
||||
}
|
||||
// #endif
|
||||
console.log(e, 'error');
|
||||
},
|
||||
// video app使用这种方式,判断直播是否结束
|
||||
ended() {
|
||||
console.log('ended');
|
||||
this.$emit('ended');
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.video-size {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
<template>
|
||||
<view :class="theme_view + ' bg-0 flex-row'" :style="'width:' + windowWidth + 'px;height:' + windowHeight + 'px;'">
|
||||
<view class="flex-1">
|
||||
<live-video src="http://live-pull-all.shopxo.vip/68f764013572f9240ca7ce6c/shopxo122.m3u8"></live-video>
|
||||
<live-video src="http://live-pull-all.shopxo.vip/68f764013572f9240ca7ce6c/shopxo122.m3u8" @ended="ended"></live-video>
|
||||
</view>
|
||||
<view class="live-content" :style="'width:' + windowWidth + 'px;height:' + windowHeight + 'px;'">
|
||||
<live-content></live-content>
|
||||
<view class="live-ended flex-row align-c jc-c" :style="'width:' + windowWidth + 'px;height:' + windowHeight + 'px;'">
|
||||
<text class="live-ended-text">直播已结束</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
@ -27,7 +29,7 @@
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.live-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
@ -36,4 +38,15 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.live-ended {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
// 添加渐变背景色
|
||||
background-image: linear-gradient(to bottom, rgba(18, 12, 39, 0.85), rgba(52, 27, 43, 0.7), rgba(92, 39, 41, 0.6), rgba(132, 51, 39, 0.7), rgba(18, 12, 39, 0.85));
|
||||
.live-ended-text {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -8,8 +8,8 @@
|
|||
<live-content></live-content>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view v-if="is_live_ended" class="live-ended flex-row align-c jc-c" :style="'width:' + windowWidth + 'px;height:' + windowHeight + 'px;'">
|
||||
<text>直播已结束</text>
|
||||
<view class="live-ended flex-row align-c jc-c">
|
||||
<text class="live-ended-text">直播已结束</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
},
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.live-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
@ -44,6 +44,14 @@
|
|||
height: 100%;
|
||||
}
|
||||
.live-ended {
|
||||
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
// 添加渐变背景色
|
||||
background-image: linear-gradient(to bottom, rgba(18, 12, 39, 0.85), rgba(52, 27, 43, 0.7), rgba(92, 39, 41, 0.6), rgba(132, 51, 39, 0.7), rgba(18, 12, 39, 0.85));
|
||||
.live-ended-text {
|
||||
color: rgba(255, 255, 255, 0.95);
|
||||
font-size: 16px;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue