业务遇到有个APP需要播放透明背景视频,穿插到AI生成的音频中,还要监听播放完成等事件。废话不多说直接上代码
<template>
<view class="sp-class" v-html="videoHtml" ref="videoContainer"></view>
</template>
<script>
export default {
data() {
return {
videoUrl: 'https://cdn.itnan.ren/demo5.webm',
videoElement: null // 存储视频元素的引用
}
},
computed: {
videoHtml() {
return` <video width = "300"
height = "300"
style = "width: 100%;height: 100%;z-index: 10080 !important; background: transparent !important;"
src = "${this.videoUrl}"
class = "transparent-video"
autoplay muted preload = "auto" / > `
}
},
mounted() {
this.$nextTick(() = > {
this.bindVideoEvents();
});
},
methods: {
bindVideoEvents() {
try {
// 方法1: 尝试直接通过 ref 获取
let container = this.$refs.videoContainer;
// 如果 ref 是一个 Vue 组件实例,尝试获取其 $el
if (container && container.$el) {
container = container.$el;
}
// 如果 ref 是数组(在某些情况下可能发生)
if (Array.isArray(container)) {
container = container[0];
if (container && container.$el) {
container = container.$el;
}
}
console.log('Container type:', typeof container, container);
if (container && container.querySelector) {
const videoElement = container.querySelector('.transparent-video');
if (videoElement) {
this.videoElement = videoElement;
this.setupTransparentVideo(videoElement);
this.addVideoEventListeners(videoElement);
} else {
console.warn('未找到 video 元素,延迟重试...');
setTimeout(() = > this.bindVideoEvents(), 100);
}
} else {
console.warn('容器不可用,延迟重试...');
setTimeout(() = > this.bindVideoEvents(), 100);
}
} catch (error) {
console.error('绑定视频事件时出错:', error);
// 延迟重试
setTimeout(() = > this.bindVideoEvents(), 100);
}
},
addVideoEventListeners(videoElement) {
// 移除可能已存在的事件监听器
this.removeVideoEventListeners(videoElement);
// 添加新的事件监听器
videoElement.addEventListener('ended', this.handleVideoEnded);
videoElement.addEventListener('error', this.handleVideoError);
videoElement.addEventListener('loadeddata', this.onVideoLoaded);
videoElement.addEventListener('canplay', this.onVideoCanPlay);
},
removeVideoEventListeners(videoElement) {
if (videoElement) {
videoElement.removeEventListener('ended', this.handleVideoEnded);
videoElement.removeEventListener('error', this.handleVideoError);
videoElement.removeEventListener('loadeddata', this.onVideoLoaded);
videoElement.removeEventListener('canplay', this.onVideoCanPlay);
}
},
setupTransparentVideo(videoElement) {
// 设置透明背景相关属性
videoElement.style.background = 'transparent';
videoElement.style.backgroundColor = 'transparent';
// 设置必要的属性
videoElement.setAttribute('playsinline', 'true');
videoElement.setAttribute('webkit-playsinline', 'true');
videoElement.setAttribute('preload', 'auto');
// 对于透明视频的特殊处理
videoElement.style.mixBlendMode = 'screen';
},
onVideoLoaded() {
console.log('透明视频加载完成');
},
onVideoCanPlay() {
console.log('透明视频可以播放');
},
handleVideoEnded() {
console.log('透明视频播放完成');
// 播放完成后的处理逻辑
this.$emit('video-ended');
// 可以在这里添加重新播放或其他逻辑
// this.restartVideo();
},
handleVideoError(e) {
console.error('透明视频播放错误:', e);
if (e.target && e.target.error) {
console.error('错误详情:', e.target.error);
}
},
// 重新播放方法
restartVideo() {
if (this.videoElement) {
this.videoElement.currentTime = 0;
this.videoElement.play().
catch (error = > {
console.error('重新播放失败:', error);
});
}
},
// 手动播放控制方法
playVideo() {
if (this.videoElement) {
this.videoElement.play().
catch (error = > {
console.error('播放失败:', error);
});
}
},
pauseVideo() {
if (this.videoElement) {
this.videoElement.pause();
}
}
},
beforeDestroy() {
// 清理事件监听
if (this.videoElement) {
this.removeVideoEventListeners(this.videoElement);
}
},
watch: {
// 如果 videoUrl 发生变化,重新绑定事件
videoUrl() {
this.$nextTick(() = > {
setTimeout(() = > this.bindVideoEvents(), 200);
});
}
}
}
</script>
<style scoped>
.sp-class {
position: fixed;
left: 0;
top: 0;
width: 750rpx;
height: 100vh;
z-index: 10080 !important;
// border: 1rpx solid red;
}
.transparent-video::cue {
display: none;
}
.transparent-video::-webkit-media-controls-panel {
background-color: transparent;
}
</style>Vue运行即可。但是需注意播放的视频需要透明才能看到结果。需合成透明底色movg格式视频(AE、PR、剪映SVIP 等专业软件),然后用ffmpeg转为webm即可
赣公网安备36010402000493
评论回复