初始設置的代碼:
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;
}