微信小程序踩坑之video组件黑屏闪现

bat365官方网站 📅 2025-11-03 07:13:48 👤 admin 👁️ 1019 ❤️ 828
微信小程序踩坑之video组件黑屏闪现

video组件即使添加poster属性,依然黑屏闪现

1.1、若 controls 属性值为 false 则设置 poster 无效:1.2、底部的黑屏1.3、objectFit="fill",但视频似乎还是没有完整填充:旁边的黑边定位问题过程:1. 样式影响2. 视频有黑边3. 视频宽高比与容器宽高比不匹配object-fit动态计算容器宽高比服务端视频预处理:将视频和容器尺寸匹配

hack方案结合父级 overflow: hidden; 子级 `css transform` / margin: -1rpx缩 放新增一个层级盖住最终方案

1.4、加载视频较完善实现:结合多次播放

1.1、若 controls 属性值为 false 则设置 poster 无效:

补加图片组件兜底,且需要ready周期时就提前加载元素,避免资源空态太久

1.2、底部的黑屏

不是背景色,未加载到的时候展示兜底图

1.3、objectFit=“fill”,但视频似乎还是没有完整填充:旁边的黑边

很遗憾,暂时并未解决,也未通过任何方式进行hack处理成功

环境:skyline引擎、调试最低版本3.6.6 机型表现:and、IOS(IOS黑边更明显,and稍细,但ios部分机型似乎可以通过margin:-1rpx 父级overflow:hidden做隐藏)

定位问题过程:

1. 样式影响

新建页面,纯video标签

2. 视频有黑边

替换线上平台其他正常视频

3. 视频宽高比与容器宽高比不匹配

object-fit

src="video.mp4"

style="width: 100%; height: 100%; object-fit: cover;"

/>

cover:保持比例填满容器,裁剪多余部分(无黑边,可能丢失边缘内容)fill:拉伸视频填满容器,不保持比例(无黑边,但可能变形)contain:保持比例完整显示,可能有黑边(默认行为)

动态计算容器宽高比

通过 JS 获取视频原始比例,动态设置容器高度:

Page({

data: { videoAspectRatio: 0 },

onVideoLoaded(e) {

const { width, height } = e.detail

const videoAspectRatio = width / height;

const systemInfo = wx.getSystemInfoSync()

const containerWidth = systemInfo.windowWidth

const containerHeight = containerWidth / videoAspectRatio

this.setData({ containerHeight });

}

})

style="width: 100%; height: {{containerHeight}}px;"

>

src="video.mp4"

style="width: 100%; height: 100%;"

bindloadedmetadata="onVideoLoaded"

/>

服务端视频预处理:将视频和容器尺寸匹配

其实,直接通过一个video标签去设置跟视频相同的尺寸即可,不设置的时候视频有默认尺寸。

hack方案

结合父级 overflow: hidden; 子级 css transform / margin: -1rpx缩 放

通过缩放视频消除黑边(适用于固定比例容器):

.video-container {

width: 100%;

height: 400rpx;

overflow: hidden;

}

// video标签

.video-content {

width: 100%;

height: 100%;

transform: scale(1.1); /* 根据实际比例调整 */

}

新增一个层级盖住

盖不住

最终方案

不是video必须场景,建议使用apng等动画方式替代video必须场景,放置一个封面图,点击全屏/放大播放(可以按尺寸处理后,背景自动黑屏)

1.4、加载视频较完善实现:结合多次播放

wx:if="{{showCoverImage}}"

src="{{videoPoster}}"

class="videoContainer-cover"

/>

id="curVideo"

class="videoContainer-video"

src="{{videoSrc}}"

poster="{{videoPoster}}"

loop="{{true}}"

autoplay="{{true}}"

muted="{{true}}"

bindloadedmetadata="onLoadedData"

binderror="onError"

objectFit="fill"

controls="{{false}}"

showFullscreenBtn="{{false}}"

showPlayBtn="{{false}}"

showProgress="{{false}}"

enablePlayGesture="{{false}}"

/>

// less

.videoContainer {

width: 100%;

height: 100%;

position: relative;

display: flex;

justify-content: center;

align-items: center;

overflow: hidden;

&-poster {

position: absolute;

top: 0;

left: 0;

right: 0;

bottom: 0;

width: 100%;

height: 100%;

z-index: 2;

border-radius: inherit;

background-color: var(--white);

}

&-video {

position: absolute;

top: 0;

left: 0;

right: 0;

bottom: 0;

width: 100%;

height: 100%;

z-index: 1;

overflow: hidden;

margin: 0;

padding: 0;

border: none;

object-fit: fill;

outline: none; /* 移除聚焦时的轮廓 */

display: block; /* 避免行内元素空隙 */

background-color: var(--white);

}

}

// 预加载单张图片

preloadImage(url: string): Promise {

return new Promise((resolve, reject) => {

wx.getImageInfo({

src: url,

success: () => {

console.log('preloadImage success');

resolve();

},

fail: (err) => reject(err),

});

});

},

/**

* 预加载视频

* 1. 创建视频上下文

* 2. 调用play()方法预加载视频(不自动播放)

*/

preloadVideo() {

try {

// 创建视频上下文: this一定要添加,不然实际play无法正常调用

const videoContext = wx.createVideoContext('Video', this);

// 加载视频

// videoContext.play();

// videoContext.pause();

} catch (error) {

console.error('preloadVideo error', error);

}

},

// 视频加载完成

async onLoadedMetaData(e) {

console.log('e.detail', e.detail);

const { width, height } = e.detail;

// 固定宽高?

console.info('mp4 onLoadedMetaData 视频加载完成 before', this.data.isVideoLoadEnd);

// 不知道为什么重复播放的话,会多次加载完成。所以做一个拦截动作

if (this.data.isVideoLoadEnd) {

return;

}

// 避免覆盖图片隐藏,视频还未正常出现抖动

setTimeout(() => {

this.setData({

showCoverImage: false,

});

}, 200);

// 设置视频相关状态

this.setData({

isVideoPlayEnd: true,

isVideoLoadEnd: true,

playVideoTimer: setTimeout(() => {

this.playVideo();

}, videoStartTime),

});

},

/**

* 播放视频方法

* 1. 检查视频是否已播放结束,避免重复播放

* 2. 控制视频最多播放 videoPlaytime 次

* 3. 捕获并处理播放过程中的异常

*/

playVideo() {

try {

// 从组件数据中获取播放次数、视频上下文和播放状态

const { playCount = 0, videoContext = null, isVideoPlayEnd = false } = this.data || {};

// 如果视频未播放结束,直接返回避免重复播放

if (!isVideoPlayEnd) {

return;

}

// 控制视频最多播放 videoPlaytime 次

if (playCount < videoPlaytime) {

// 更新播放次数

this.setData({

playCount: playCount + 1,

});

// 调用视频上下文播放方法

videoContext?.play();

} else {

this.clearExistingTimer();

}

} catch (error) {

// 捕获并记录播放错误

console.error('playVideo error', error);

}

},

// 视频加载出错

onError(info) {

console.error('视频加载出错');

this.setData({ showPoster: true });

},

/**

* 视频播放结束事件处理

* 1. 清除现有的定时器

* 2. 设置视频结束状态并启动新的定时器,在指定间隔后重新播放视频

*/

onEnded() {

// 清除现有的定时器

this.clearExistingTimer();

// 设置视频结束状态并启动新的定时器

this.setData({

isVideoPlayEnd: true,

playVideoTimer: setTimeout(() => {

this.playVideo();

}, videoInterTime),

});

},

相关养生推荐

《熹妃传》主角职业及随从分析汇总 34个随从分析
bat365官方网站

《熹妃传》主角职业及随从分析汇总 34个随从分析

📅 08-24 👁️ 1469
2025年社团活动成果与反思总结(10篇)
365bet体育手机

2025年社团活动成果与反思总结(10篇)

📅 07-05 👁️ 4961
Tempescope 天气盒子
亚洲365bet比分

Tempescope 天气盒子

📅 10-01 👁️ 5040
韩国环境改善:绿色发展引领未来,韩国环境好吗
bat365官方网站

韩国环境改善:绿色发展引领未来,韩国环境好吗

📅 07-26 👁️ 8257
格式工厂怎么用?-格式工厂使用教程
亚洲365bet比分

格式工厂怎么用?-格式工厂使用教程

📅 07-24 👁️ 4237
月最低工资标准
bat365官方网站

月最低工资标准

📅 08-04 👁️ 5146