<template> <view class="swiper-container"> <swiper class="swiper" circular :indicator-dots="false" :circular="circular" :next-margin="nextMargin" :autoplay="autoplay" :interval="interval" :duration="duration" :style="style" @change="onSwiperChange"> <template v-for="(item, index) in items"> <swiper-item :key="index"> <view class="image-wrapper" @tap="onImageClick(item)"> <image v-if="item.src" :mode="imageMode" :src="item.src" :style="imageStyle"/> <slot v-else :scope="item"></slot> <view class="video-play" v-if="item.url && item.url.indexOf('.mp4') !== -1"> <view class="iconfont icon-playcircle"></view> </view> </view> </swiper-item> </template> </swiper> <!-- 自定义指示点 --> <view v-if="indicatorDots" class="custom-indicator" :class="{ 'morphing': indicatoDotsStyle === 'morphing' }"> <view v-for="(item, index) in items" :key="index" class="dot" :class="{ 'active': current === index }" ></view> </view> <van-overlay :show="showOverlay" @tap="onClickHideOverlay"> <view class="overlay-wrapper"> <video v-if="videoUrl" :src="videoUrl" controls autoplay loop @tap.stop></video> </view> </van-overlay> </view> </template> <script> import VanOverlay from '@/wxcomponents/vant/overlay/index' export default { options: { styleIsolation: 'shared' }, components: { VanOverlay }, props: { items: Array, borderRadius: { type: Number }, nextMargin: { type: String, default: '' }, height: { type: Number, default: 400 }, imageWidth: { type: Number, default: 0 }, imageHeight: { type: Number, default: 0 }, imageMode: { type: String, default: 'aspectFill' // 参考https://zh.uniapp.dcloud.io/component/image.html }, indicatoDotsStyle: { type: String, default: 'default' // or 'morphing' }, indicatorDots: { type: Boolean, default: true }, circular: { type: Boolean, default: true }, autoplay: { type: Boolean, default: true }, interval: { type: Number, default: 5000 }, duration: { type: Number, default: 500 } }, computed: { style() { return 'height:' + this.height + 'rpx;' }, imageStyle() { let style = 'height:' + (this.imageHeight || this.height) + 'rpx;' if (this.imageWidth) { style += 'width:' + this.imageWidth + 'rpx;' } if (this.borderRadius) { style += 'border-radius:' + this.borderRadius + 'rpx;' } return style } }, watch: { }, data() { return { showOverlay: false, videoUrl: '', current: 0 } }, created() { }, mounted() { }, methods: { onClickHideOverlay() { this.showOverlay = false }, onSwiperChange(e) { this.current = e.detail.current }, onImageClick(item) { if (item.url) { if (item.url.indexOf('.mp4') !== -1) { this.videoUrl = item.url this.showOverlay = true } else if (item.url.indexOf('http') === -1) { uni.navigateTo({ url: item.url }) } else { uni.navigateTo({ url: '/pages/index/webview?url=' + item.url }) } } } } } </script> <style lang="scss" scoped> .image-wrapper { position: relative; .video-play{ @include display-flex-center; position: absolute; top: 0; bottom: 0; right: 0; left: 0; width: 82rpx; height: 82rpx; border-radius: 50%; margin: auto; background-color: rgba(229, 117, 25, 0.5); z-index: 1; .iconfont{ color: #FFFFFF; font-size: 62rpx; } } image{ width: 100%; } } .overlay-wrapper{ @include display-flex-center; height: 100%; video{ width: 100%; } } .swiper-container{ position: relative; } /* 自定义指示点样式 */ .custom-indicator { position: absolute; bottom: 24rpx; width: 100%; display: flex; justify-content: center; margin-top: 10rpx; &.morphing { .dot{ margin: 0 5rpx; } .dot.active{ width: 26rpx; border-radius: 8rpx; background-color: white; } } } .dot { width: 12rpx; height: 12rpx; border-radius: 50%; background-color: #D9D9D9; margin: 0 2.5rpx; &.active { background-color: $buttonPrimaryColor; /* 当前激活的指示点颜色 */ } } </style>