video 在uni-app ios左右滑动进度条失效,播放按钮层级遮挡头部标题和返回按钮

video 在uni-app ios左右滑动进度条失效,播放按钮层级遮挡头部标题和返回按钮

开发环境 版本号 项目创建方式
Windows 11 CLI

产品分类:

uniapp/App

PC开发环境操作系统:

Windows

手机系统:

iOS

手机系统版本号:

iOS 18

手机厂商:

苹果

手机机型:

苹果12

页面类型:

nvue

vue版本:

vue3

打包方式:

云端

项目创建方式:

CLI

CLI版本号:

3.0.0-4060620250520001

示例代码:

<template> <view> <view> </view> </view> </view> </template> <script> import videoCacheUtil from '@/utils/videoCache.js'; export default { props: { videoId: { type: String, default: '' }, videoUrl: { type: String, default: '' }, poster: { type: String, default: '' }, direction: { type: Number, default: -90 } }, data() { return { videoSrc: '', controlsType: false, cached: false, controls: false, isPlaying: false, duration: 0, current: 0, isFullScreen: false, controlsBoxFullTop: 0, }; }, mounted() { // #ifdef H5 this.videoContext = this.$refs.videoRef; // #endif // #ifndef H5 this.videoContext = uni.createVideoContext(this.videoId); // #endif this.getVideoDurationNative(); setTimeout(() => { this.controlsType = true }, 500) }, // videoCacheUtil.clearAllCache() // 视频缓存 this.handleSetCache() }, onLoad() {}, methods: { /** * 视频缓存相关 * [@param](/user/param) event */ async handleSetCache() { // #ifdef H5 this.videoSrc = this.videoUrl // #endif // #ifndef H5 // 获取可播放路径(优先使用缓存) this.videoSrc = await videoCacheUtil.getPlayablePath(this.videoUrl, (progress) => {}, async () => { this.videoContext.pause() this.controlsType = false this.videoSrc = await videoCacheUtil.getPlayablePath(this.videoUrl) setTimeout(() => { this.handleEnded() this.videoContext.play() setTimeout(() => { this.videoContext.seek(this.current) this.controlsType = true },50) },50) }); // #endif }, handlefullscreenchange(event) { if (event.detail.fullScreen) { // Entered fullscreen mode clearTimeout(this.timer); this.hideControls(); } else {} }, // 正在拖动进度条 handleSeeking() { clearTimeout(this.timer); this.hideControls(); }, handleEnded() { // Entered fullscreen mode clearTimeout(this.timer); this.controls = false; }, // 点击显示/隐藏控制条 handleControls() { this.controls = !this.controls; if (this.controls) { clearTimeout(this.timer); this.hideControls(); } }, // 自动隐藏控制条 hideControls() { this.timer = setTimeout(() => { this.controls = false; }, 8000); }, // 获取视频时长 getVideoDurationNative() { // #ifdef H5 // H5下通过loadedmetadata事件获取时长 // #endif // #ifndef H5 uni.getVideoInfo({ src: this.videoUrl, success: (res) => { this.duration = res.duration }, fail(err) { } }) // #endif }, onLoadedMetadata(e) { // H5下获取视频时长 this.duration = e.target.duration || (e.detail && e.detail.duration) || 0; }, // 播放暂停视频 togglePlay(e) { // #ifdef H5 if (e) { this.$refs.videoRef && this.$refs.videoRef.play(); this.isPlaying = true; } else { this.$refs.videoRef && this.$refs.videoRef.pause(); this.isPlaying = false; } // #endif // #ifndef H5 if (e) { this.videoContext.play(); this.isPlaying = true; } else { this.videoContext.pause(); this.isPlaying = false; } // #endif }, handlePlay() { this.isPlaying = true; }, handlePause() { this.isPlaying = false; }, videoErrorCallback: function(e) { uni.showToast({ title: '播放失败', icon: 'none', }) }, secondToMinute(second) { let sec = Math.floor(second % 60); let minute = Math.floor((second / 60) % 60); let hour = Math.floor(second / 3600); return `${hour < 10 ? '0' + hour : hour}:${minute < 10 ? '0' + minute : minute}:${sec < 10 ? '0' + sec : sec}`; }, xiazai() { // #ifdef H5 const a = document.createElement('a'); a.href = this.videoUrl; a.download = ''; document.body.appendChild(a); a.click(); document.body.removeChild(a); // #endif // #ifndef H5 uni.showModal({ title: '下载', content: '是否下载该视频', success: (res) => { if (res.confirm) { uni.downloadFile({ url: this.videoUrl, success: res => { if (res.statusCode === 200) { // iOS需要将文件保存到本地相册或沙盒目录 uni.saveVideoToPhotosAlbum({ filePath: res.tempFilePath, success: () => { uni.showToast({ title: '视频保存成功', icon: 'none' }); }, fail: err => { uni.showToast({ title: '保存失败: ' + err .errMsg }); } }); } }, fail: err => { uni.showToast({ title: '下载失败: ' + err.errMsg }); } }); } else if (res.cancel) { } } }); // #endif }, enterFullScreen(e) { this.videoContext.requestFullScreen(); this.isFullScreen = e; if (this.isFullScreen) { const sysInfo = uni.getSystemInfoSync(); // 控件条高度 60px,nvue下1px=1px const controlsHeight = 60; // 屏幕高度 const screenHeight = sysInfo.windowWidth; // 计算top this.controlsBoxFullTop = screenHeight - controlsHeight; } else { this.controlsBoxFullTop = 0 } }, videoTimeUpdate(e) { if (e && e.detail && e.detail.currentTime) { this.current = e.detail.currentTime; } }, } }; </script> <style scoped lang="scss"> .xiazai { position: absolute; right: 50rpx; top: 10rpx; width: 40rpx; height: 40rpx; } .controls-box-xiazai-full { position: absolute; top: 0; left: 0; right: 0; height: 60rpx; width: 750rpx; background-color: rgba(0, 0, 0, 0.6); } .xiazai-btn { position: absolute; right: 50rpx; top: 0rpx; z-index: 999; } .text1 { color: #ffffff; } .show { transition: transform 0.3s ease-in-out; transform: translateY(0px); } .hide { transition: transform 0.3s ease-in-out; transform: translateY(-50px); /* 上移 */ } .sunny-video { position: relative; } .controls-box { position: absolute; bottom: 0; left: 0; right: 0; height: 100rpx; width: 750rpx; background-color: rgba(0, 0, 0, 0.6); display: flex; flex-direction: row; align-items: center; justify-content: flex-start; padding: 0 20rpx; z-index: 10; } .play-btn { width: 80rpx; height: 80rpx; display: flex; align-items: center; justify-content: center; } .btn-icon { width: 60rpx; height: 80rpx; display: flex; align-items: center; justify-content: center; margin-left: 10rpx; } .uni-slider {} .time-text { color: #fff; font-size: 24rpx; margin-left: 10rpx; width: 50px; } .controls-box-full { position: absolute; left: 0; right: 0; background-color: rgba(0, 0, 0, 0.4); height: 60px; display: flex; flex-direction: row; align-items: center; justify-content: flex-start; padding: 0 20rpx; z-index: 10; } .play-btn { width: 60px; height: 60px; display: flex; align-items: center; justify-content: center; } .time-text { color: #ffffff; font-size: 12px; } .uni-slider { flex: 1; } </style>

更多关于video 在uni-app ios左右滑动进度条失效,播放按钮层级遮挡头部标题和返回按钮的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于video 在uni-app ios左右滑动进度条失效,播放按钮层级遮挡头部标题和返回按钮的实战教程也可以访问 https://www.itying.com/category-93-b0.html


在 iOS nvue 页面中,video 组件左右滑动进度条失效和播放按钮层级遮挡是常见问题,主要与 iOS 原生 video 控件的渲染机制相关。

进度条滑动失效解决方案:

  1. 检查 controls 属性的动态切换逻辑。示例代码中通过 setTimeout 延迟设置 controlsType = true,这可能导致 iOS 视频控件初始化异常。建议在 onReady 生命周期中启用控件:
onReady() {
  this.controlsType = true;
}
  1. 确认视频源加载状态。iOS 对未正确加载的视频会禁用进度条交互,可在 loadedmetadata 事件后重置控件:
onLoadedMetadata(e) {
  this.duration = e.detail.duration;
  this.videoContext && this.videoContext.seek(0); // 重置播放位置
}

层级遮挡问题处理:

  1. 使用 cover-view 时需确保其位于 video 组件内部,且通过 z-index 控制层级。示例中 xiazai-btnz-index: 999 在 iOS 可能失效,建议改为固定值 z-index: 9999

  2. 避免自定义控件与原生控件重叠。iOS 原生播放按钮无法直接覆盖,可通过隐藏原生控件并完全自定义控制栏实现:

// 隐藏原生控件
controlsType: false
// 使用 cover-view 完全自定义控制栏
<cover-view class="custom-controls">
  <!-- 自定义播放/暂停按钮 -->
</cover-view>
  1. 全屏模式下,通过 fullscreenchange 事件动态调整自定义元素位置:
handlefullscreenchange(event) {
  if (event.detail.fullScreen) {
    // 调整自定义控件位置避免遮挡
    this.controlsBoxFullTop = uni.getSystemInfoSync().windowHeight - 60;
  }
}
回到顶部