yunshangxie/tuniao-ui/components/tn-stack-swiper/tn-stack-swiper.vue

285 lines
7.4 KiB
Vue

<template>
<view
class="tn-stack-swiper-class tn-stack-swiper"
:style="{
width: $tn.string.getLengthUnitValue(width),
height: $tn.string.getLengthUnitValue(height)
}"
:list="swiperList"
:itemData="itemData"
:currentIndex="swiperIndex"
:autoplayFlag="autoplayFlag"
:change:list="wxs.listObserver"
:change:itemData="wxs.itemDataObserver"
:change:currentIndex="wxs.swiperIndexChange"
:change:autoplayFlag="wxs.autoplayFlagChange"
>
<block v-for="(item, index) in list" :key="index">
<!-- #ifdef MP-WEIXIN -->
<view
class="tn-stack-swiper__item tn-stack-swiper__item__transition"
:class="[`tn-stack-swiper__item--${direction}`]"
:data-index="index"
:data-switchRate="switchRate"
@touchstart="wxs.touchStart"
:catch:touchmove="touching?wxs.touchMove:''"
:catch:touchend="touching?wxs.touchEnd:''"
>
<image class="tn-stack-swiper__image" mode="aspectFill" :src="item.image"></image>
</view>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<view
class="tn-stack-swiper__item"
:class="[`tn-stack-swiper__item--${direction}`]"
:data-index="index"
:data-switchRate="switchRate"
@touchstart="wxs.touchStart"
@touchmove="wxs.touchMove"
@touchend="wxs.touchEnd"
>
<image class="tn-stack-swiper__image" mode="aspectFill" :src="item.image"></image>
</view>
<!-- #endif -->
</block>
</view>
</template>
<!-- #ifdef MP-WEIXIN -->
<script src="./index.wxs" lang="wxs" module="wxs"></script>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<script src="./index-h5.wxs" lang="wxs" module="wxs"></script>
<!-- #endif -->
<script>
export default {
name: 'tn-stack-swiper',
props: {
// 显示图片的列表数据
// {
// // 图片地址
// image: 'xxx'
// }
list: {
type: Array,
default() {
return []
}
},
// 轮播容器的宽度 rpx
width: {
type: [String, Number],
default: '100%'
},
// 轮播容器的高度 rpx
height: {
type: [String, Number],
default: 500
},
// 自动切换
autoplay: {
type: Boolean,
default: false
},
// 自动切换时长 ms
interval: {
type: Number,
default: 5000
},
// 滑动切换移动比例, [0 - 100]
// 比例相对于item的宽度
switchRate: {
type: Number,
default: 30
},
// 缩放比例 [0-1]
scaleRate: {
type: Number,
default: 0.1
},
// 下一轮播偏移比例
translateRate: {
type: Number,
default: 16
},
// 下一轮播透明比例
opacityRate: {
type: Number,
default:10
},
// 滑动方向
// horizontal -> 水平 vertical -> 垂直
direction: {
type: String,
default: 'horizontal'
}
},
data() {
return {
autoplayTimer: null,
// window窗口的宽度
windowWidth: 0,
// 轮播item的宽度
swiperItemWidth: 0,
// 轮播item的高度
swiperItemHeight: 0,
// 当前选中的轮播item
swiperIndex: -1,
// 标记是否开始触摸
touching: true,
// 轮播列表信息
swiperList: [],
// 标记当前是否为自动播放
autoplayFlag: false
}
},
computed: {
itemData() {
return {
windowWidth: this.windowWidth,
itemWidth: this.swiperItemWidth,
itemHeight: this.swiperItemHeight,
direction: this.direction,
autoplaying: this.autoplayFlag
}
}
},
watch: {
list(val) {
this.swiperList = []
this.$nextTick(() => {
this.initSwiperRectInfo()
})
},
autoplay(val) {
if (!val) {
this.clearAutoPlayTimer()
} else {
this.setAutoPlay()
}
}
},
created() {
this.autoplayFlag = this.autoplay
},
mounted() {
this.$nextTick(() => {
this.initSwiperRectInfo()
})
},
destroyed() {
this.clearAutoPlayTimer()
},
methods: {
// 初始化轮播容器信息
async initSwiperRectInfo() {
// 用于一开始绑定事件
// this.touching = true
// 获取轮播item的宽度
const swiperItemRect = await this._tGetRect('.tn-stack-swiper__item')
if (!swiperItemRect || !swiperItemRect.width || !swiperItemRect.height) {
setTimeout(() => {
this.initSwiperRectInfo()
}, 50)
return
}
this.swiperItemWidth = swiperItemRect.width
this.swiperItemHeight = swiperItemRect.height
// this.touching = false
// 获取系统的窗口宽度信息
const systemInfo = uni.getSystemInfoSync()
this.windowWidth = systemInfo.windowWidth
this.swiperIndex = 0
// 设置对应swiper元素的位置和层级信息
this.swiperList = this.list.map((item, index) => {
const scale = 1 - (this.scaleRate * index)
if (this.direction === 'horizontal') {
item.translateX = ((index * this.translateRate) * 0.01 * this.swiperItemWidth)
} else if (this.direction === 'vertical') {
item.translateY = ((index * this.translateRate) * 0.01 * this.swiperItemHeight)
}
item.opacity = (1 - ((index * this.opacityRate) * 0.01))
item.zIndex = this.list.length - index
item.scale = scale <= 0 ? 0 : scale
return item
})
this.setAutoPlay()
},
// 设置自动切换轮播
setAutoPlay() {
if (this.autoplay) {
this.clearAutoPlayTimer()
this.autoplayFlag = true
this.autoplayTimer = setInterval(() => {
this.swiperIndex = this.swiperIndex + 1 > this.swiperList.length - 1 ? 0 : this.swiperIndex + 1
}, this.interval)
}
},
// 清除自动切换定时器
clearAutoPlayTimer() {
if (this.autoplayTimer != null) {
this.autoplayFlag = false
clearInterval(this.autoplayTimer)
}
},
// 修改轮播选中index
changeSwiperIndex(e) {
// console.log(e.index);
this.swiperIndex = e.index
this.$emit('change', { index: e.index })
},
// 修改触摸状态
changeTouchState(e) {
this.touching = e.touching
},
// 打印日志
printLog(data) {
console.log("log", data);
}
}
}
</script>
<style lang="scss" scoped>
.tn-stack-swiper {
position: relative;
&__item {
position: absolute;
border-radius: 20rpx;
overflow: hidden;
&--horizontal {
width: 88%;
height: 100%;
transform-origin: left center;
}
&--vertical {
width: 100%;
height: 88%;
transform-origin: top center;
}
&__transition {
transition-property: transform,opacity;
transition-duration: 0.25s;
transition-timing-function: ease-out;
// transition: transform, opacity 0.25s ease-in-out !important;
}
}
&__image {
width: 100%;
height: 100%;
}
}
</style>