因为uniapp的video标签层级太高,所以我这边引用了原生的video标签

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

因为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" />

如果遇到问题私信我!!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值