video同层播放层级过高遮挡模拟暂停按钮的问题

本文详细介绍了在iOS和Android平台上使用微信内置浏览器播放视频时的同层播放适配问题,包括解决视频在swiper组件中播放时的显示问题,以及实现视频圆角和模拟暂停按钮的显示逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在ios和android上有显示的区别,如果你只是显示一个普通的网页,只需要在iOS上加上webkit-playsinline="true" 安卓上x5-video-player-type="h5" x5-video-player-fullscreen="true" x5-video-orientation="portraint",即可实现在微信上的同层播放;iOS和安卓显示和播放没有问题;
如果你跟我一样想要把视频放到swiper里,且不是在第一页播放视频,并想要视频有圆角。那么问题就来了。首先在swiper非第一屏播放安卓会出现的问题是竖屏只有声音没有图像,我尝试了好久只需要去掉安卓部分的同层播放代码即可,即去掉x5-video-player-type="h5";如果视频在swiper里,你肯定会有这样的需求,就是滑动到非视频页的时候,暂停视频,并出现一个模拟的暂停按钮在视频上方。这里可以这样写:

const mySwiper = new Swiper('.swiper-container', {
    direction: 'vertical',
    on: {
      slideChangeTransitionEnd: function() {
        if (this.activeIndex != 1) {
          //暂停视频代码
        }
      }
    }
  })

这里定义一个是否显示暂停的按钮的变量showPoster,来显示暂停模拟按钮和隐藏video;
这里显示播放按钮必须和视频显示必须呈反相关,因为不这样作会有很多默认的bug,导致video_container的overflow:hidden不生效,无法显示圆角,这算是一种比较圆滑的做法了;我试过将video的position设为fixed 这样虽然能正常显示和隐藏模拟的点击按钮,但会让父级的overflow:hidden失效。无法显示视频圆角。代码大概如下:

<div class="video_container">
<div class="clickVideo" @click="playVideo()" v-show="showPoster">
  <img src="../assets/点击播放按钮.png"/>
</div> 
<video
  v-show="!showPoster" 
  src="../assets/QQ20181214-221408-HD.mp4"
  id="video"
  preload="auto"

  x5-video-player-fullscreen="true"
  x5-video-orientation="portraint"

  airplay="allow"
  x-webkit-airplay="allow"

  playsinline="true" 
  webkit-playsinline="true"
  style="object-fit:fill"
>
<!-- 
  controls="controls" 待加
  poster="../assets/share.png"
  安卓同层播放属性
  x5-video-player-type="h5" //启用同层播放。取值固定为'h5'。  启用之后仅安卓在swiper第二页播放竖屏不显示画面所以这里暂不用
  x5-video-player-fullscreen="true" //设置为 true 是防止横屏
   x5-video-orientation="portraint" //竖屏 landscape 横屏

  ios同层播放属性
  airplay="allow"
  x-webkit-airplay="allow"
  playsinline="true" //IOS微信浏览器支持小窗内播放
  webkit-playsinline="true" // 这个属性是ios 10中设置可以让视频在小窗内播放,也就是不是全屏播放
 -->
    </video>
</div>

<style lang="less">
    .video_container{
        @w: 670px/2;
        @h: 377px/2;
        @borderRadius: 50px;
        width:@w;
        height:@h;
        margin:100px auto;
        border-radius:@borderRadius;
        overflow: hidden;
        position: relative;
        .clickVideo{
          position: absolute;
          width:@w;
          height:@h;
          background:#ccc;
          z-index:999;
          & > img {
            @play:60px;
            width:@play;
            height:@play;
            position:absolute;
            top:50%;
            left:50%;
            transform: translate(-50%, -50%)
          }
        }
        video{
          width:@w;
          height:@h;
        }
    }
</style>

注:如果你在swiper的非第一页使用视频,在安卓手机上会出现视频黑屏但可以播放声音的问题,这个时候就可以不使用安卓的同层播放,即不使用x5-video-player-type="h5"即可。
同层播放的资料参考链接:http://www.cnblogs.com/jinjin...

<template> <view class="video-container"> <!-- 视频列表 --> <swiper class="swiper" :autoplay="false" :circular="false" :vertical="true" :current="current" @change="onSwiperChange" > <swiper-item v-for="(video, index) in videoList" :key="index" class="swiper-item"> <view class="video-wrapper" v-if="index === current"> <video :id="'video-' + index" :src="video.url" :show-fullscreen-btn="true" :controls="true" :enable-progress-gesture="false" object-fit="cover" controls @timeupdate="onTimeUpdate(index, $event)" ></video> </view> <!-- 视频信息 --> <view class="video-info"> <view class="title">{{ video.title }}</view> <view class="author-info"> <image class="author-avatar" :src="video.author.avatar" mode="aspectFill"></image> <text class="author-name">{{ video.author.name }}</text> </view> </view> <!-- 点赞和评论 --> <view class="actions"> <button class="action-btn" @click="toggleLike(index)"> <text class="iconfont">{{ video.isLiked ? '♥' : '♡' }}</text> <text class="action-count">{{ video.likes }}</text> </button> <button class="action-btn" @click="openCommentModal(index)"> <text class="iconfont">💬</text> <text class="action-count">{{ video.comments.length }}</text> </button> </view> </swiper-item> </swiper> <!-- 评论弹窗 --> <uni-popup ref="commentPopup" type="bottom"> <view class="comment-modal"> <view class="modal-header"> <text class="modal-title">评论</text> <button class="close-button" @click="closeCommentModal">✕</button> </view> <view class="modal-content"> <!-- 评论输入框 --> <textarea class="comment-input" v-model="commentText" placeholder="发表评论..." @confirm="submitComment" /> <button class="submit-button" @click="submitComment">发送</button> <!-- 评论列表 --> <view class="comment-list"> <view class="comment-item" v-for="(comment, idx) in currentComments" :key="idx"> <text class="comment-user">{{ comment.user }}</text> <text class="comment-content">{{ comment.content }}</text> </view> </view> </view> </view> </uni-popup> </view> </template> <script setup> import { ref, onMounted } from 'vue'; const db = uniCloud.database() const current = ref(0); const videoList = ref([]); const progress = ref(0); const currentTime = ref('00:00'); const duration = ref('00:00'); let videoContext = null; let currentVideoIndex = ref(0); const commentText = ref(''); const commentPopup = ref(null); const currentComments = ref([]); const isLoading = ref(false); // 初始化视频列表 onMounted(() => { getVideoData(); }); // 获取视频数据 const getVideoData = async () => { isLoading.value = true; try { const queryCondition = db.command.and( db.command.neq(undefined), db.command.neq('') ); const res = await db.collection('news-articles') .where({ videoshow: queryCondition }) .get(); videoList.value = res.result.data.map(item => ({ url: item.videoshow, title: item.title, author: { avatar: item.author_avatar, name: item.author_name }, likes: item.likes || 0, comments: item.comments || [], isLiked: false })); if (videoList.value.length > 0) { loadVideo(current.value); } else { console.log('没有找到符合条件的视频'); } } catch (err) { console.error('获取视频数据失败:', err); } finally { isLoading.value = false; } }; // 加载视频 const loadVideo = (index) => { videoContext = uni.createVideoContext(`video-${index}`); videoContext.play(); updateVideoInfo(index); }; // 更新视频信息 const updateVideoInfo = (index) => { const video = videoList.value[index]; currentVideoIndex.value = index; currentComments.value = video.comments; currentTime.value = '00:00'; progress.value = 0; }; // 格式化时间 const formatTime = (seconds) => { const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; }; // 滑动切换视频 const onSwiperChange = (e) => { const index = e.detail.current; if (videoContext) { videoContext.pause(); videoContext = null; } current.value = index; loadVideo(index); currentTime.value = '00:00'; progress.value = 0; }; // 视频时间更新 const onTimeUpdate = (index, e) => { if (index === current.value) { currentTime.value = formatTime(e.target.currentTime); progress.value = (e.target.currentTime / e.target.duration) * 100; } }; // 切换点赞状态 const toggleLike = (index) => { const video = videoList.value[index]; video.isLiked = !video.isLiked; if (video.isLiked) { video.likes++; } else { video.likes--; } }; // 打开评论弹窗 const openCommentModal = (index) => { currentComments.value = videoList.value[index].comments; commentPopup.value.open(); }; // 关闭评论弹窗 const closeCommentModal = () => { commentPopup.value.close(); }; // 提交评论 const submitComment = () => { if (commentText.value.trim() !== '') { const newComment = { user: '当前用户', content: commentText.value }; videoList.value[currentVideoIndex.value].comments.unshift(newComment); currentComments.value.unshift(newComment); commentText.value = ''; commentPopup.value.close(); } }; </script> <style scoped> .video-container { width: 100%; height: 100vh; background-color: #000; overflow: hidden; } .swiper { width: 100%; height: 100%; } .swiper-item { width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; } .video-wrapper { position: relative; width: 100%; height: 100%; } video { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; } .video-info { position: absolute; bottom: 150px; left: 0; width: 100%; padding: 20px; color: #fff; background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent); } .title { font-size: 18px; font-weight: bold; margin-bottom: 10px; } .author-info { display: flex; align-items: center; } .author-avatar { width: 40px; height: 40px; border-radius: 50%; margin-right: 10px; } .author-name { font-size: 14px; } .actions { position: absolute; bottom: 60px; right: 20px; display: flex; flex-direction: column; align-items: center; } .action-btn { background: rgba(0, 0, 0, 0.5); color: #fff; border: none; border-radius: 50%; width: 50px; height: 50px; display: flex; flex-direction: column; align-items: center; margin-bottom: 15px; } .iconfont { font-size: 20px; margin-bottom: 5px; } .action-count { font-size: 12px; } .comment-modal { background-color: #fff; width: 100%; padding: 15px; border-radius: 10px 10px 0 0; } .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .modal-title { font-size: 16px; font-weight: bold; } .close-button { background: none; border: none; font-size: 18px; } .modal-content { height: 400px; overflow-y: auto; } .comment-input { width: 100%; height: 80px; margin-bottom: 10px; padding: 10px; background-color: #f5f5f5; border-radius: 5px; font-size: 14px; } .submit-button { width: 100%; padding: 10px; background-color: #007aff; color: #fff; border: none; border-radius: 5px; } .comment-list { margin-top: 15px; } .comment-item { padding: 10px 0; border-bottom: 1px solid #eee; } .comment-user { font-weight: bold; margin-bottom: 5px; } .comment-content { color: #333; } </style>是vue3代码,请修改代码,解决在app端中video在swipe滑动时,出现video组件位置不稳定,且遮挡其他view的问题
最新发布
07-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值