提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
因为uniapp的video标签层级太高,所以我这边引用了原生的video标签 因为uniapp的video标签没有倍速功能而且层级太高只能够利用内置组件进行重写。
一、首先先封装一个组件
这个组件里面要写两个JS,前者是为了引用后者的,直接看完整代码吧!
二、完整代码
1.HTML
代码如下:
<template>
<view v-html="videoHtml" id="dom-video" class="dom-video" :eventDrive="eventDrive"
:change:eventDrive="domVideo.eventHandle" :videoSrc="videoSrc" :change:videoSrc="domVideo.srcChange"
:videoProps="videoProps" :change:videoProps="domVideo.propsChange" :randomNum="randomNum"
:change:randomNum="domVideo.randomNumChange" />
</template>
2.第一个js
因为是封装的组件所以要传值(第一个js):
<script>
export default {
props: {
src: {
type: String,
default: ''
},
autoplay: {
type: Boolean,
default: false
},
loop: {
type: Boolean,
default: false
},
controls: {
type: Boolean,
default: false
},
objectFit: {
type: String,
default: 'contain'
},
muted: {
type: Boolean,
default: false
},
poster: {
type: String,
default: ''
},
},
// 数据状态
data() {
return {
videoHtml: '',
videoSrc: '',
eventDrive: null,
videoProps: {},
randomNum: Math.floor(Math.random() * 100000000 + 1)
}
},
watch: {
// 监听视频资源文件更新
src: {
handler(val) {
if (!val) return
this.initVideoHtml()
setTimeout(() => {
this.videoSrc = val
}, 0)
},
immediate: true
},
// 监听首次加载
autoplay: {
handler(val) {
this.videoProps.autoplay = val
},
immediate: true
},
},
// 生命周期
mounted() {
this.initVideoHtml()
},
// 方法
methods: {
// 将video的事件传递给父组件
videoEvent(data) {
// console.log('向父组件传递事件 =>', data)
this.$emit("videoEvent", data)
},
changePlaybackProgress(data) {
this.$emit("changePlaybackProgress", data)
},
// 初始化视频
initVideoHtml() {
this.videoHtml = `<video
src="${this.src}"
id="dom-html-video_${this.randomNum}"
class="dom-html-video"
${this.autoplay ? 'autoplay' : ''}
${this.loop ? 'loop' : ''}
${this.controls ? 'controls' : ''}
${this.muted ? 'muted' : ''}
poster="${this.src}?x-oss-process=video/snapshot,t_0,f_jpg"
preload="auto"
playsinline
webkit-playsinline
width="100%"
height="100%"
controlslist="nodownload"
style="object-fit: ${this.objectFit};padding:0;"
>
<source src="${this.src}" type="video/mp4">
<source src="${this.src}" type="video/ogg">
<source src="${this.src}" type="video/webm">
</video>
`
// console.log('视频html =>', this.videoHtml)
},
resetEventDrive() {
this.eventDrive = null
},
// 将service层的事件/数据 => 传递给renderjs层
play() {
this.eventDrive = 'play'
},
pause() {
this.eventDrive = 'pause'
},
stop() {
this.eventDrive = 'stop'
},
}
}
</script>
3.第二个js
<script module="domVideo" lang="renderjs">
export default {
data() {
return {
video: null,
timeSetInterval: null,
num: '',
options: {},
}
},
mounted() {
this.initVideoEvent()
},
methods: {
myplay() {
this.getPlaybackProgress(true)
this.$ownerInstance.callMethod('videoEvent', 'play')
},
mypause() {
this.getPlaybackProgress(false)
this.$ownerInstance.callMethod('videoEvent', 'pause')
},
myended() {
this.getPlaybackProgress(false)
this.$ownerInstance.callMethod('videoEvent', 'ended')
this.$ownerInstance.callMethod('resetEventDrive')
},
initVideoEvent() {
setTimeout(() => {
let video = document.getElementById(`dom-html-video_${this.num}`)
this.video = video
// 将之前的视频事件移出监听 必须要移出不移出定时器没有办法停止
video.removeEventListener("play", this.myplay)
video.removeEventListener("pause", this.mypause)
video.removeEventListener("ended", this.myended)
// 监听视频事件/重新监听视频事件
video.addEventListener('play', this.myplay)
video.addEventListener('pause', this.mypause)
video.addEventListener('ended', this.myended)
}, 100)
// this.getPlaybackProgress(false)
},
eventHandle(eventType) {
if (eventType) {
this.video = document.getElementById(`dom-html-video_${this.num}`)
if (eventType === 'play') {
setTimeout(() => {
this.video.play();
}, 350)
return
} else if (eventType === 'pause') {
setTimeout(() => {
this.video.pause();
}, 350)
} else if (eventType === 'stop') {
this.video.stop()
}
}
},
//这里是视频链接切换的时候
srcChange(val) {
this.video = document.getElementById(`dom-html-video_${this.num}`)
// 实现视频的第一帧作为封面,避免视频展示黑屏
this.initVideoEvent()
setTimeout(() => {
let video = document.getElementById(`dom-html-video_${this.num}`)
video.addEventListener('loadedmetadata', () => {
let {
autoplay
} = this.options
// video.play()
// if (!autoplay) {
// video.pause()
// }
})
}, 10)
},
propsChange(obj) {
this.options = obj
},
randomNumChange(val) {
this.num = val
},
getPlaybackProgress(bool) { //这里是为了获取播放的时间
// console.log(bool)
if (bool) {
this.timeSetInterval = setInterval(() => {
let currentTime = this.video.currentTime
let duration = this.video.duration
this.$ownerInstance.callMethod('changePlaybackProgress', {
currentTime,
duration
})
}, 1000)
} else {
clearInterval(this.timeSetInterval)
this.timeSetInterval = null
}
},
}
}
</script>
3.css样式
<style lang="scss" scoped>
.dom-video {
overflow: hidden;
height: 100%;
padding: 0;
&-height {
height: 100%;
}
}
</style>
4.完整代码
<!-- eslint-disable -->
<template>
<view v-html="videoHtml" id="dom-video" class="dom-video" :eventDrive="eventDrive"
:change:eventDrive="domVideo.eventHandle" :videoSrc="videoSrc" :change:videoSrc="domVideo.srcChange"
:videoProps="videoProps" :change:videoProps="domVideo.propsChange" :randomNum="randomNum"
:change:randomNum="domVideo.randomNumChange" />
</template>
<script>
export default {
props: {
src: {
type: String,
default: ''
},
autoplay: {
type: Boolean,
default: false
},
loop: {
type: Boolean,
default: false
},
controls: {
type: Boolean,
default: false
},
objectFit: {
type: String,
default: 'contain'
},
muted: {
type: Boolean,
default: false
},
poster: {
type: String,
default: ''
},
},
// 数据状态
data() {
return {
videoHtml: '',
videoSrc: '',
eventDrive: null,
videoProps: {},
randomNum: Math.floor(Math.random() * 100000000 + 1)
}
},
watch: {
// 监听视频资源文件更新
src: {
handler(val) {
if (!val) return
this.initVideoHtml()
setTimeout(() => {
this.videoSrc = val
}, 0)
},
immediate: true
},
// 监听首次加载
autoplay: {
handler(val) {
this.videoProps.autoplay = val
},
immediate: true
},
},
// 生命周期
mounted() {
this.initVideoHtml()
},
// 方法
methods: {
// 将video的事件传递给父组件
videoEvent(data) {
// console.log('向父组件传递事件 =>', data)
this.$emit("videoEvent", data)
},
changePlaybackProgress(data) {
this.$emit("changePlaybackProgress", data)
},
// 初始化视频
initVideoHtml() {
this.videoHtml = `<video
src="${this.src}"
id="dom-html-video_${this.randomNum}"
class="dom-html-video"
${this.autoplay ? 'autoplay' : ''}
${this.loop ? 'loop' : ''}
${this.controls ? 'controls' : ''}
${this.muted ? 'muted' : ''}
poster="${this.src}?x-oss-process=video/snapshot,t_0,f_jpg"
preload="auto"
playsinline
webkit-playsinline
width="100%"
height="100%"
controlslist="nodownload"
style="object-fit: ${this.objectFit};padding:0;"
>
<source src="${this.src}" type="video/mp4">
<source src="${this.src}" type="video/ogg">
<source src="${this.src}" type="video/webm">
</video>
`
// console.log('视频html =>', this.videoHtml)
},
resetEventDrive() {
this.eventDrive = null
},
// 将service层的事件/数据 => 传递给renderjs层
play() {
this.eventDrive = 'play'
},
pause() {
this.eventDrive = 'pause'
},
stop() {
this.eventDrive = 'stop'
},
}
}
</script>
<script module="domVideo" lang="renderjs">
export default {
data() {
return {
video: null,
timeSetInterval: null,
num: '',
options: {},
}
},
mounted() {
this.initVideoEvent()
},
methods: {
myplay() {
this.getPlaybackProgress(true)
this.$ownerInstance.callMethod('videoEvent', 'play')
},
mypause() {
this.getPlaybackProgress(false)
this.$ownerInstance.callMethod('videoEvent', 'pause')
},
myended() {
this.getPlaybackProgress(false)
this.$ownerInstance.callMethod('videoEvent', 'ended')
this.$ownerInstance.callMethod('resetEventDrive')
},
initVideoEvent() {
setTimeout(() => {
let video = document.getElementById(`dom-html-video_${this.num}`)
this.video = video
// 将之前的视频事件移出监听
video.removeEventListener("play", this.myplay)
video.removeEventListener("pause", this.mypause)
video.removeEventListener("ended", this.myended)
// 监听视频事件/重新监听视频事件
video.addEventListener('play', this.myplay)
video.addEventListener('pause', this.mypause)
video.addEventListener('ended', this.myended)
}, 100)
// this.getPlaybackProgress(false)
},
eventHandle(eventType) {
if (eventType) {
this.video = document.getElementById(`dom-html-video_${this.num}`)
if (eventType === 'play') {
setTimeout(() => {
this.video.play();
}, 350)
return
} else if (eventType === 'pause') {
setTimeout(() => {
this.video.pause();
}, 350)
} else if (eventType === 'stop') {
this.video.stop()
}
}
},
srcChange(val) {
this.video = document.getElementById(`dom-html-video_${this.num}`)
// 实现视频的第一帧作为封面,避免视频展示黑屏
this.initVideoEvent()
setTimeout(() => {
let video = document.getElementById(`dom-html-video_${this.num}`)
video.addEventListener('loadedmetadata', () => {
let {
autoplay
} = this.options
// video.play()
// if (!autoplay) {
// video.pause()
// }
})
}, 10)
},
propsChange(obj) {
this.options = obj
},
randomNumChange(val) {
this.num = val
},
getPlaybackProgress(bool) {
// console.log(bool)
if (bool) {
this.timeSetInterval = setInterval(() => {
let currentTime = this.video.currentTime
let duration = this.video.duration
this.$ownerInstance.callMethod('changePlaybackProgress', {
currentTime,
duration
})
}, 1000)
} else {
clearInterval(this.timeSetInterval)
this.timeSetInterval = null
}
// console.log(time)
// clearInterval(this.timeSetInterval)
// this.timeSetInterval = null
// this.timeSetInterval = setInterval(() => {
// let currentTime = this.video.currentTime
// let duration = this.video.duration
// this.$ownerInstance.callMethod('changePlaybackProgress', {
// currentTime,
// duration
// })
// }, time)
// else {
// clearInterval(this.timeSetInterval)
// this.timeSetInterval = null
// }
},
}
}
</script>
<style lang="scss" scoped>
.dom-video {
overflow: hidden;
height: 100%;
padding: 0;
&-height {
height: 100%;
}
}
</style>
5.在那个页面用就直接引用
import XXX from '@/components/XXX/XXX.vue'
直接在用
<DomVideo ref="domVideo" @videoEvent="method.videoEvent"
@changePlaybackProgress="method.changePlaybackProgress" :src="ImgUrl" class="domVideo"
:controls="true" />
如果遇到问题私信我!!