小程序视频播放,与父视图一致等样式设置
初始设置的代码:
WXML的代码
<view class="card-wrapper"> <!-- 视频播放容器(默认隐藏) --> <view class="video-container" wx:if="{{isPlaying}}"> <video id="cardVideo" class="card-video" src="{{item.videoUrl}}" autoplay controls bindplay="onVideoPlay" bindpause="onVideoPause" bindended="onVideoEnd" ></video> <view class="video-close-btn" bindtap="togglePlay"> <image src="https://images.biliq.com/images/miniprogram/paopao2.0/paopaoCard/close.png" mode="aspectFit" /> </view> </view> <!-- 封面图容器(播放时隐藏) --> <view class="banner-mask" wx:if="{{!isPlaying}}"> <image class="banner-img" src="{{item.cover}}" mode="aspectFill" /> <!-- 播放按钮 --> <view class="play-mask" bindtap="togglePlay"> <image class="play-icon" src="https://images.biliq.com/images/miniprogram/paopao2.0/paopaoCard/play.png" mode="aspectFit" /> </view> <!-- 点赞、转发、导航 --> <view class="action-bar-wrapper"> <actionBar class="action-bar" item="{{item}}" bind:action="onAction" /> </view> </view> <!-- 名称区域 --> <view class="desc-mask" wx:if="{{!isPlaying}}"> <!-- 名称 --> <text class="banner-title">{{item.title}}</text> <!-- 挂载件 --> <actionMount wx:if="{{item.ismount}}" class="has-mount" item="{{item}}" bind:action="onAction" /> <!-- 无挂载 --> <view wx:elif="{{!item.ismount}}" class="no-mount" item="{{item}}" bind:action="onAction" /> <!-- 详情 --> <view wx:if="{{!item.ismount}}" class="more-mask" bindtap="handleDatail"> <image class="more-img" src="https://images.biliq.com/images/miniprogram/paopao2.0/paopaoCard/more.png" /> </view> </view> <!-- 标签区域 --> <view class="tag-list" wx:if="{{!isPlaying}}"> <block wx:for="{{item.tags}}" wx:key="index" wx:if="{{index < 3}}"> <view class="tag-mask {{item.spotag ? 'has-spot' : ''}}"> <image class="spot-tag" wx:if="{{item.spotag}}" src="https://images.biliq.com/images/miniprogram/paopao2.0/paopaoCard/spotag.png" mode="aspectFit" /> <text class="tag">{{item.text}}</text> </view> </block> </view> </view>
JS的代码
Component({ properties: { item: Object }, data: { isPlaying: false, videoContext: null }, methods: { // 切换播放状态 togglePlay() { if (this.data.isPlaying) { // 如果正在播放,则暂停并隐藏视频 this.data.videoContext.pause(); this.setData({ isPlaying: false }); } else { // 如果未播放,则显示视频并播放 this.setData({ isPlaying: true }, () => { this.data.videoContext = wx.createVideoContext('cardVideo', this); this.data.videoContext.play(); }); } }, // 视频开始播放 onVideoPlay() { console.log('视频开始播放'); }, // 视频暂停 onVideoPause() { console.log('视频已暂停'); }, // 视频播放结束 onVideoEnd() { this.setData({ isPlaying: false }); }, // 其他原有方法... onAction(e) { // 原有逻辑 }, handleDatail() { // 原有逻辑 } }, // 组件卸载时销毁视频实例 detached() { if (this.data.videoContext) { this.data.videoContext.pause(); } } });
WXSS的代码
.card-wrapper { position: relative; width: 100%; border-radius: 12rpx; overflow: hidden; } /* 视频容器样式 */ .video-container { position: relative; width: 100%; height: 0; padding-bottom: 56.25%; /* 16:9 比例 */ } .card-video { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .video-close-btn { position: absolute; top: 20rpx; right: 20rpx; width: 60rpx; height: 60rpx; z-index: 10; } .video-close-btn image { width: 100%; height: 100%; } /* 原有样式保持不变 */ .banner-mask { position: relative; width: 100%; height: 0; padding-bottom: 56.25%; /* 16:9 比例 */ } .banner-img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .play-mask { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; background-color: rgba(0, 0, 0, 0.3); } .play-icon { width: 100rpx; height: 100rpx; } /* 其他原有样式... */
上述代码展示效果如下
上述代码可以实现视频播放,但是样式不是很好看,我们可以增加一些设置,比如视频和父视图的卡片一样,视频居中展示播放等等,下面是优化后的代码。
WXML的代码
<view class="card-wrapper">
<!-- 视频播放容器(默认隐藏) -->
<view class="video-container" wx:if="{{isPlaying}}">
<!-- 修改为绝对定位的视频包装器 -->
<view class="video-wrapper">
<video
id="cardVideo"
class="card-video"
src="{{item.videoUrl}}"
autoplay
controls
bindplay="onVideoPlay"
bindpause="onVideoPause"
bindended="onVideoEnd"
></video>
</view>
<!-- 关闭按钮 -->
<view class="video-close-btn" bindtap="togglePlay">
<image src="https://images.biliq.com/images/miniprogram/paopao2.0/paopaoCard/close.png" mode="aspectFit" />
</view>
</view>
<!-- 封面图容器(播放时隐藏) -->
<view class="banner-mask" wx:if="{{!isPlaying}}">
<!-- 封面 -->
<image class="banner-img" src="{{item.cover}}" mode="aspectFill" />
<!-- 播放 -->
<view class="play-mask" bindtap="togglePlay">
<image class="play-icon" src="{{isPlaying ? '' : 'https://images.biliq.com/images/miniprogram/paopao2.0/paopaoCard/play.png'}}" mode="aspectFit}}" />
</view>
<!-- 点赞、转发 -->
<view class="action-bar-wrapper">
<actionBar class="action-bar" item="{{item}}" bind:action="onAction" />
</view>
</view>
<!-- 名称区域 -->
<view class="desc-mask" wx:if="{{!isPlaying}}">
<text class="banner-title">{{item.name}}</text>
<view class="more-mask" bind:tap="onDatail">
<image class="more-img" src="https://images.biliq.com/images/miniprogram/paopao2.0/paopaoCard/more.png" />
</view>
<!-- 标签区域 -->
<view class="tag-list">
<block wx:for="{{item.tags}}" wx:key="index" wx:if="{{index < 3}}">
<view class="tag-mask">
<text class="tag">{{item.text}}</text>
</view>
</block>
</view>
</view>
</view>
WXSS的代码
.card-wrapper{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
color: #fff;
padding: 0;
}
/* 视频容器样式 - 关键修改 */
.video-container {
position: relative;
width: 100%;
height: 100%;
background: #000;
display: flex;
flex-direction: column; /* 改为列方向布局 */
}
/* 视频包装器 - 移除绝对定位 */
.video-wrapper {
flex: 1; /* 占据剩余空间 */
position: relative;
width: 100%;
padding-bottom: 56.25%; /* 保持16:9比例 */
}
/* 视频样式调整 */
.card-video {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
}
/* 强制原生控件在底部 */
.card-video::webkit-media-controls {
position: absolute;
bottom: 0;
width: 100%;
}
.video-close-btn {
position: absolute;
top: 35rpx;
right: 20rpx;
width: 60rpx;
height: 60rpx;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
}
.video-close-btn image {
width: 100%;
height: 100%;
}
/* 封面图 */
.banner-mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
.banner-img {
width: 100%;
height: 100%;
border-radius: 20rpx;
}
.play-mask{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 88rpx;
height: 88rpx;
padding: 0;
background: none;
display: flex;
justify-content: center;
align-items: center;
}
.play-icon{
width: 100%;
height: 100%;
}
/* 描述区域 */
.desc-mask{
position: absolute;
display: inline-flex;/* 改为inline-flex使宽度自适应内容 */
align-items: center;
left: 30rpx;
height: 104rpx;
bottom: 40rpx;
border-radius: 20rpx;
background-color: rgba(29, 52, 59, 0.4);
backdrop-filter: blur(10rpx);
padding: 0 24rpx;
gap: 5rpx; /* title 与 more-mask 间距 5rpx */
}
.banner-title{
height: 48rpx;
font-weight: 600;
font-size: 34rpx;
color: #FFFFFF;
white-space: nowrap; /* 防止换行 */
}
.more-mask{
flex-shrink: 0;
width: 45rpx;
height: 45rpx;
display: flex;
align-items: center;
justify-content: center;
}
.more-img{
width: 26rpx;
height: 26rpx;
}
/* 标签 */
.tag-list{
position: absolute;
left: 5rpx;
bottom: 114rpx;
display: flex;
flex-wrap: wrap;
gap: 10rpx;
align-items: center;
padding: 6rpx 12rpx;
z-index: 1; /* 确保在desc-mask上层 */
}
.tag-mask{
display: inline-flex; /* 行内弹性布局 */
align-items: center;
background: rgba(0, 0, 0, 0.4);
border-radius: 22rpx;
height: 44rpx;
padding: 5rpx 15rpx;/* 动态宽度由内容撑开 */
}
.tag{
font-weight: 500;
font-size: 20rpx;
color: #E0ED42;
line-height: 28rpx;
text-align: justify;
/* 确保文字不换行 */
white-space: nowrap;
margin-right: 5rpx;
}
/* 收藏、转发 */
.action-bar-wrapper {
position: absolute;
right: 30rpx;
bottom: 30rpx;
width: 60rpx;
height: 380rpx;
z-index: 999;
}
.action-bar {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
gap: 20rpx;
}