货无忧
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

412 lines
8.8 KiB

<template>
<view class="hd-swiper">
<swiper
class="screen-swiper"
@change="change"
@animationfinish="animationfinish"
:indicator-dots="indicatorDots"
:indicator-active-color="indicatorActiveColor"
:indicator-color="indicatorColor"
:autoplay="autoplay && playing"
:current="current"
:interval="interval"
:duration="duration"
:circular="circular"
:vertical="vertical"
:previous-margin="vertical ? '0px' : previousMargin"
:next-margin="vertical ? '0px' : nextMargin"
:display-multiple-items="displayMultipleItems"
:skip-hidden-item-layout="skipHiddenItemLayout"
:style="{ height: swiperHeight + 'px', 'min-height': '0px' }"
>
<swiper-item class="swiper-item" v-for="(item, index) in swiperList" :key="index" @tap="clickItem(index)">
<view v-if="item[imageKey] && !item[videoKey]" class="swiper-item-view">
<image
:src="item[imageKey]"
:style="{
height: swiperHeight + 'px',
width: card ? '94%' : '100%',
marginLeft: card ? '3%' : '0px',
borderRadius: card ? '8px' : '0px'
}"
mode="aspectFill"
/>
<text
v-if="showTextTip"
class="swiperText"
:style="{
bottom: textStyleBottom + '%',
right: textStyleRight + '%',
color: textStyleColor,
background: textStyleBgcolor,
'font-size': CommonUtil.addUnit(CommonUtil.getPx(textStyleSize), 'px')
}"
>
{{ item[textKey] }}
</text>
</view>
<view v-if="item[videoKey]" class="swiper-item-view">
<video
:src="item[videoKey]"
@play="play"
@pause="pause"
:style="{ height: swiperHeight + 'px' }"
loop
muted
:autoplay="videoAutoplay"
objectFit="cover"
/>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script lang="ts" setup>
import { getCurrentInstance, onMounted, ref } from 'vue'
import { CommonUtil } from '../../libs/utils/CommonUtil'
/**
* Swipeer 轮播图
*
*/
interface Props {
/**
* 图片数组
*/
swiperList: Array<Record<string, any>>
/**
* 是否自动播放视频
*/
videoAutoplay?: boolean
/**
* 视频映射的键(字段名)
*/
videoKey?: string
/**
* 图片映射的键(字段名)
*/
imageKey?: string
/**
* 文字说明映射的键(字段名)
*/
textKey?: string
/**
* 是否展示图片文字说明
*/
showTextTip?: boolean
/**
* 图片文字大小
*/
textStyleSize?: number
/**
* 图片文字底部距离
*/
textStyleBottom?: number
/**
* 图片文字右侧距离
*/
textStyleRight?: number
/**
* 图片文字颜色
*/
textStyleColor?: string
/**
* 图片文字背景色
*/
textStyleBgcolor?: string
/**
* 宽高比 推荐 w/h => 2
*/
rate?: number
/**
* 是否跳过未显示的滑块布局,设为 true 可优化复杂情况下的滑动性能,但会丢失隐藏状态滑块的布局信息
* App、微信小程序支持
*/
skipHiddenItemLayout?: boolean
/**
* 同时显示的滑块数量
* 支付宝钉钉不支持
*/
displayMultipleItems?: number
/**
* 后边距,可用于露出后一项的一小部分,接受 px 和 rpx 值 app-nvue、字节跳动小程序、飞书小程序不支持
*/
nextMargin?: string
/**
* 前边距,可用于露出前一项的一小部分,接受 px 和 rpx 值 app-nvue、字节跳动小程序、飞书小程序不支持
*/
previousMargin?: string
/**
* 滑动方向是否为纵向 卡牌 不支持纵向以及同时显示的2块以上滑块数量
*/
vertical?: boolean
/**
* 是否采用衔接滑动
*/
circular?: boolean
/**
* 滑动动画时长
*/
duration?: number
/**
* 自动切换时间间隔
*/
interval?: number
/**
* 当前所在滑块的下标
*/
current?: number
/**
* 是否自动切换
*/
autoplay?: boolean
/**
* 指示点颜色
*/
indicatorColor?: string
/**
* 当前选中的指示点颜色
*/
indicatorActiveColor?: string
/**
* 是否显示面板指示点
*/
indicatorDots?: boolean
/**
* 是否卡片样式
*/
card?: boolean
}
const props = withDefaults(defineProps<Props>(), {
/**
* 图片数组
*/
swiperList: () => [],
/**
* 是否自动播放视频
*/
videoAutoplay: false,
/**
* 视频映射的键(字段名)
*/
videoKey: 'video',
/**
* 图片映射的键(字段名)
*/
imageKey: 'img',
/**
* 文字说明映射的键(字段名)
*/
textKey: 'text',
/**
* 是否展示图片文字说明
*/
showTextTip: false,
/**
* 图片文字大小
*/
textStyleSize: 12,
/**
* 图片文字底部距离
*/
textStyleBottom: 5,
/**
* 图片文字右侧距离
*/
textStyleRight: 5,
/**
* 图片文字颜色
*/
textStyleColor: '#ffffff',
/**
* 图片文字背景色
*/
textStyleBgcolor: 'transparent',
/**
* 宽高比 推荐 w/h => 2
*/
rate: 2,
/**
* 是否跳过未显示的滑块布局,设为 true 可优化复杂情况下的滑动性能,但会丢失隐藏状态滑块的布局信息
* App、微信小程序支持
*/
skipHiddenItemLayout: false,
/**
* 同时显示的滑块数量
* 支付宝钉钉不支持
*/
displayMultipleItems: 1,
/**
* 后边距,可用于露出后一项的一小部分,接受 px 和 rpx 值 app-nvue、字节跳动小程序、飞书小程序不支持
*/
nextMargin: '0px',
/**
* 前边距,可用于露出前一项的一小部分,接受 px 和 rpx 值 app-nvue、字节跳动小程序、飞书小程序不支持
*/
previousMargin: '0px',
/**
* 滑动方向是否为纵向 卡牌 不支持纵向以及同时显示的2块以上滑块数量
*/
vertical: true,
/**
* 是否采用衔接滑动
*/
circular: true,
/**
* 滑动动画时长
*/
duration: 400,
/**
* 自动切换时间间隔
*/
interval: 2500,
/**
* 当前所在滑块的下标
*/
current: 0,
/**
* 是否自动切换
*/
autoplay: true,
/**
* 指示点颜色
*/
indicatorColor: '#CCCCCC',
/**
* 当前选中的指示点颜色
*/
indicatorActiveColor: '#ffffff',
/**
* 是否显示面板指示点
*/
indicatorDots: true,
/**
* 是否卡片样式
*/
card: false
})
const playing = ref<boolean>(true) // 是否在轮播
const cardCur = ref<number>(0) // 轮播当前项
const swiperHeight = ref<number>(0) // 轮播图片高度
const { proxy } = getCurrentInstance() as any
onMounted(() => {
const query = uni
.createSelectorQuery()
// #ifndef MP-ALIPAY
.in(proxy)
// #endif
query
.select('.swiper-item')
.boundingClientRect((data: any) => {
if (data != null) {
swiperHeight.value = data.width / props.rate
}
})
.exec()
})
/**
* 视频开始播放
*/
function play() {
playing.value = false
}
/**
* 视频暂停播放
*/
function pause() {
playing.value = true
}
const emit = defineEmits(['clickItem', 'change', 'animationfinish'])
function clickItem(index: number) {
if (props.swiperList.length > 0) {
/**
* 滑块被点击时触发
* @arg value:Object 滑块值
*/
emit('clickItem', props.swiperList[index])
}
}
function change(e) {
/**
* 激活滑块变更时触发
* @arg value:Object 滑块值
*/
emit('change', e)
}
function animationfinish(e) {
cardCur.value = e.detail.current
/**
* 滑块动画结束时触发
* @arg value:Object 滑块值
*/
emit('animationfinish', e)
}
</script>
<style lang="scss" scoped>
.hd-swiper {
width: 100%;
.swiper-item-view {
height: 100%;
width: 100%;
position: relative;
}
.swiperText {
position: absolute;
color: #ffffff;
z-index: 2;
border-radius: 2px;
padding: 0 2px;
}
.screen-swiper image {
width: 100%;
}
.screen-swiper video,
.swiper-item video {
width: 100%;
display: block;
height: 100%;
}
}
// .hd-swiper--card {
// .swiper-item {
// overflow: initial;
// box-sizing: border-box;
// width: 100%;
// }
// .swiper-item-view {
// display: block;
// height: 100%;
// border-radius: 5px;
// transform: scale(0.93, 0.8);
// opacity: 0.7;
// transition: all 0.1s ease-in 0s;
// overflow: hidden;
// box-sizing: border-box;
// }
// .swiper-item--cur view {
// transform: initial;
// opacity: 1;
// transition: all 0.1s ease-in 0s;
// }
// .swiper-item--pre view {
// transform: scale(0.93, 0.8);
// padding-left: 5%;
// }
// .swiper-item--after view {
// transform: scale(0.93, 0.8);
// padding-right: 5%;
// }
// }
</style>