<template>
|
|
<view class="banner" :style="{ height: height }">
|
|
<swiper
|
|
:indicator-dots="false"
|
|
:autoplay="true"
|
|
:interval="3000"
|
|
:duration="500"
|
|
circular
|
|
:style="{ width: '100%', height: height }"
|
|
>
|
|
<swiper-item v-for="(item, index) in bannerList" :key="item.id || index">
|
|
<view v-if="item.type == 1" class="video-container">
|
|
<!-- 预览状态:显示封面图 -->
|
|
<image
|
|
v-if="!videoPlayingStates[index]"
|
|
:src="item.image || ''"
|
|
mode="aspectFill"
|
|
style="width: 100%; height: 100%;"
|
|
class="video-poster"
|
|
@click="playVideoFullscreen(item, index)"
|
|
/>
|
|
<!-- 播放状态:显示视频 -->
|
|
<video
|
|
v-else
|
|
:id="`${videoIdPrefix}-${index}`"
|
|
:src="item.voUrl"
|
|
:autoplay="true"
|
|
:muted="false"
|
|
:loop="false"
|
|
:controls="true"
|
|
:show-play-btn="true"
|
|
:show-center-play-btn="false"
|
|
:show-fullscreen-btn="true"
|
|
:show-progress="true"
|
|
:show-mute-btn="true"
|
|
:enable-progress-gesture="true"
|
|
:enable-play-gesture="true"
|
|
object-fit="cover"
|
|
style="width: 100%; height: 100%;"
|
|
@fullscreenchange="onFullscreenChange"
|
|
@play="onVideoPlay(index)"
|
|
@pause="onVideoPause(index)"
|
|
@ended="onVideoEnded(index)"
|
|
></video>
|
|
<!-- 播放按钮覆盖层 -->
|
|
<view v-if="!videoPlayingStates[index]" class="video-overlay" @click="playVideoFullscreen(item, index)">
|
|
<view class="play-button-large">
|
|
<view class="play-triangle"></view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<image v-else :src="item.image" mode="aspectFill" style="width: 100%; height: 100%;" @click="onImageClick(item, index)" />
|
|
</swiper-item>
|
|
</swiper>
|
|
|
|
<!-- 备用静态图片,当没有轮播图数据时显示 -->
|
|
<image v-if="!bannerList || bannerList.length === 0" :src="fallbackImage" mode="aspectFill" style="width: 100%; height: 100%;" />
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: 'BannerSwiper',
|
|
props: {
|
|
// 轮播图数据
|
|
bannerList: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
// 轮播图高度
|
|
height: {
|
|
type: String,
|
|
default: '400rpx'
|
|
},
|
|
// 备用图片
|
|
fallbackImage: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
// 视频ID前缀,用于区分不同页面的视频
|
|
videoIdPrefix: {
|
|
type: String,
|
|
default: 'video'
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
videoPlayingStates: {} // 记录每个视频的播放状态
|
|
}
|
|
},
|
|
methods: {
|
|
// 视频全屏播放
|
|
playVideoFullscreen(item, index) {
|
|
if (!this.videoPlayingStates[index]) {
|
|
// 第一次点击:显示视频并开始播放
|
|
this.$set(this.videoPlayingStates, index, true)
|
|
// 等待视频元素渲染后再进行操作
|
|
this.$nextTick(() => {
|
|
setTimeout(() => {
|
|
const videoContext = uni.createVideoContext(`${this.videoIdPrefix}-${index}`, this)
|
|
if (videoContext) {
|
|
// 直接进入全屏播放,强制竖屏
|
|
videoContext.requestFullScreen({
|
|
direction: 0 // 竖屏方向,0代表竖屏,1代表横屏,-1自动
|
|
})
|
|
}
|
|
}, 200)
|
|
})
|
|
}
|
|
},
|
|
|
|
// 图片点击事件
|
|
onImageClick(item, index) {
|
|
this.$emit('image-click', { item, index })
|
|
},
|
|
|
|
// 视频播放事件
|
|
onVideoPlay(index) {
|
|
this.$set(this.videoPlayingStates, index, true)
|
|
},
|
|
|
|
// 视频暂停事件
|
|
onVideoPause(index) {
|
|
this.$set(this.videoPlayingStates, index, false)
|
|
},
|
|
|
|
// 视频结束事件
|
|
onVideoEnded(index) {
|
|
// 视频播放结束,回到预览状态
|
|
this.$set(this.videoPlayingStates, index, false)
|
|
},
|
|
|
|
// 全屏状态改变事件
|
|
onFullscreenChange(e) {
|
|
console.log('全屏状态改变:', e.detail)
|
|
const videoIndex = e.target.id.replace(`${this.videoIdPrefix}-`, '')
|
|
|
|
if (e.detail.fullScreen) {
|
|
// 进入全屏时,不做任何操作
|
|
console.log('进入全屏模式,方向:', e.detail.direction)
|
|
} else {
|
|
// 退出全屏时,回到预览状态
|
|
console.log('退出全屏模式,回到预览状态')
|
|
this.$set(this.videoPlayingStates, videoIndex, false)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.banner {
|
|
width: 100%;
|
|
position: relative;
|
|
overflow: hidden;
|
|
border-radius: 0 0 30rpx 30rpx;
|
|
|
|
image {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.video-container {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
|
|
.video-poster {
|
|
cursor: pointer;
|
|
transition: transform 0.2s ease;
|
|
|
|
&:active {
|
|
transform: scale(0.98);
|
|
}
|
|
}
|
|
|
|
.video-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0, 0, 0, 0.4);
|
|
z-index: 10;
|
|
cursor: pointer;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
.play-button-large {
|
|
width: 120rpx;
|
|
height: 120rpx;
|
|
background: transparent;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
backdrop-filter: blur(10rpx);
|
|
transition: all 0.3s ease;
|
|
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.3);
|
|
|
|
&:active {
|
|
transform: scale(0.9);
|
|
background: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.play-triangle {
|
|
width: 0;
|
|
height: 0;
|
|
border-left: 24rpx solid #fff;
|
|
border-top: 18rpx solid transparent;
|
|
border-bottom: 18rpx solid transparent;
|
|
margin-left: 8rpx;
|
|
transition: all 0.3s ease;
|
|
filter: drop-shadow(0 2rpx 4rpx rgba(0, 0, 0, 0.3));
|
|
}
|
|
}
|
|
|
|
&:hover .play-button-large {
|
|
transform: scale(1.1);
|
|
box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.4);
|
|
|
|
.play-triangle {
|
|
border-left-color: #ff8917;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|