278 lines
8.9 KiB
Vue
278 lines
8.9 KiB
Vue
<template>
|
||
<!-- #ifdef MP-WEIXIN -->
|
||
<view
|
||
class="tn-c-swiper-item"
|
||
:style="[swiperStyle]"
|
||
:itemData="itemData"
|
||
:currentIndex="currentIndex"
|
||
:containerData="containerData"
|
||
:change:itemData="wxs.itemDataObserver"
|
||
:change:currentIndex="wxs.currentIndexObserver"
|
||
:change:containerData="wxs.containerDataObserver"
|
||
@touchstart="wxs.touchStart"
|
||
:catch:touchmove="touching?wxs.touchMove:''"
|
||
:catch:touchend="touching?wxs.touchEnd:''"
|
||
>
|
||
<view class="item__container tn-c-swiper-item__container" :style="[containerStyle]">
|
||
<slot></slot>
|
||
</view>
|
||
</view>
|
||
<!-- #endif -->
|
||
<!-- #ifndef MP-WEIXIN -->
|
||
<view
|
||
class="tn-c-swiper-item"
|
||
:style="[swiperStyle]"
|
||
:itemData="itemData"
|
||
:currentIndex="currentIndex"
|
||
:containerData="containerData"
|
||
:change:itemData="wxs.itemDataObserver"
|
||
:change:currentIndex="wxs.currentIndexObserver"
|
||
:change:containerData="wxs.containerDataObserver"
|
||
@touchstart="wxs.touchStart"
|
||
@touchmove="wxs.touchMove"
|
||
@touchend="wxs.touchEnd"
|
||
>
|
||
<view class="item__container tn-c-swiper-item__container" :style="[containerStyle]">
|
||
<slot></slot>
|
||
</view>
|
||
</view>
|
||
<!-- #endif -->
|
||
</template>
|
||
|
||
<script src="./index.wxs" lang="wxs" module="wxs"></script>
|
||
<script>
|
||
export default {
|
||
name: 'tn-custom-swiper-item',
|
||
props: {
|
||
|
||
},
|
||
computed: {
|
||
// swiperItem公共数据
|
||
itemData() {
|
||
return {
|
||
index: this.index,
|
||
itemWidth: this.itemWidth,
|
||
itemHeight: this.itemHeight,
|
||
itemTop: this.itemTop,
|
||
itemLeft: this.itemLeft
|
||
}
|
||
},
|
||
currentIndex() {
|
||
return this.parentData.currentIndex
|
||
},
|
||
containerData() {
|
||
return {
|
||
duration: this.parentData.duration,
|
||
animationFinish: this.parentData.swiperContainerAnimationFinish,
|
||
circular: this.parentData.circular,
|
||
swiperItemLength: this.swiperItemLength,
|
||
vertical: this.parentData.vertical
|
||
}
|
||
},
|
||
swiperStyle() {
|
||
let style = {}
|
||
style.transform = `translate3d(${this.translateX}%, ${this.translateY}%, 0px)`
|
||
return style
|
||
},
|
||
containerStyle() {
|
||
let style = {}
|
||
if (this.parentData.customSwiperStyle && Object.keys(this.parentData.customSwiperStyle).length > 0) {
|
||
style = this.parentData.customSwiperStyle
|
||
}
|
||
if ((this.currentIndex === 0 && this.index === this.swiperItemLength - 1) || (this.index === this.currentIndex - 1) &&
|
||
(this.parentData.prevSwiperStyle && Object.keys(this.parentData.prevSwiperStyle).length > 0)
|
||
) {
|
||
// 前一个swiperItem
|
||
const copyStyle = JSON.parse(JSON.stringify(style))
|
||
style = Object.assign(copyStyle, this.parentData.prevSwiperStyle)
|
||
}
|
||
if ((this.currentIndex === this.swiperItemLength - 1 && this.index === 0) || (this.index === this.currentIndex + 1) &&
|
||
(this.parentData.nextSwiperStyle && Object.keys(this.parentData.nextSwiperStyle).length > 0)
|
||
) {
|
||
// 后一个swiperItem
|
||
const copyStyle = JSON.parse(JSON.stringify(style))
|
||
style = Object.assign(copyStyle, this.parentData.nextSwiperStyle)
|
||
}
|
||
return style
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
// 父组件参数
|
||
parentData: {
|
||
duration: 500,
|
||
currentIndex: 0,
|
||
swiperContainerAnimationFinish: false,
|
||
circular: false,
|
||
vertical: false,
|
||
prevSwiperStyle: {},
|
||
customSwiperStyle: {},
|
||
nextSwiperStyle: {}
|
||
},
|
||
// 标记当前是否正在触摸
|
||
touching: true,
|
||
// 当前swiperItem的偏移位置
|
||
translateX: 0,
|
||
translateY: 0,
|
||
// 当前swiperItem的宽高
|
||
itemWidth: 0,
|
||
itemHeight: 0,
|
||
// 当前swiperItem的位置信息
|
||
itemTop: 0,
|
||
itemLeft: 0,
|
||
// 当前swiperItem的状态 prev current next
|
||
status: 'current',
|
||
// 当前swiperItem的index序号
|
||
index: 0,
|
||
// swiperItem的的数量
|
||
swiperItemLength: 0
|
||
}
|
||
},
|
||
created() {
|
||
this.parent = false
|
||
this.updateParentData()
|
||
// 获取当前父组件children的数量作为当前swiperItem的序号
|
||
this.index = this.parent.children.length
|
||
this.parent && this.parent.children.push(this)
|
||
},
|
||
mounted() {
|
||
this.$nextTick(() => {
|
||
this.initSwiperItem()
|
||
})
|
||
},
|
||
methods: {
|
||
// 初始化swiperItem
|
||
initSwiperItem() {
|
||
this.getSwiperItemRect(() => {
|
||
this.parent.updateAllSwiperItemStyle()
|
||
this.parentData.swiperContainerAnimationFinish = true
|
||
})
|
||
},
|
||
// 获取swiperItem的信息
|
||
async getSwiperItemRect(callback) {
|
||
const swiperItemRes = await this._tGetRect('.tn-c-swiper-item')
|
||
if (!swiperItemRes.height || !swiperItemRes.width) {
|
||
setTimeout(() => {
|
||
this.getSwiperItemRect()
|
||
}, 30)
|
||
return
|
||
}
|
||
|
||
this.itemWidth = swiperItemRes.width
|
||
this.itemHeight = swiperItemRes.height
|
||
this.itemTop = swiperItemRes.top
|
||
this.itemLeft = swiperItemRes.left
|
||
callback && callback()
|
||
},
|
||
// 更新swiperItem样式
|
||
updateSwiperItemStyle(swiperItemLength, currentIndex = undefined) {
|
||
currentIndex = currentIndex != undefined ? currentIndex : this.parentData.currentIndex
|
||
this.swiperItemLength = swiperItemLength
|
||
// 根据当前swiperItem的序号设置偏移位置
|
||
// 判断当前swiperItem是否为第一个,如果是则将最后的swiperItem移动到当前的前一个位置(即最前面)
|
||
if (currentIndex === 0 && this.index === swiperItemLength - 1) {
|
||
if (this.parentData.vertical) {
|
||
this.translateX = 0
|
||
this.translateY = -100
|
||
} else {
|
||
this.translateX = -100
|
||
this.translateY = 0
|
||
}
|
||
}
|
||
// 判断当前swiperItem是否为最后一个,如果是则将最前的swiperItem移动到当前的后一个位置(即最后面)
|
||
else if (currentIndex === swiperItemLength - 1 && this.index === 0) {
|
||
if (this.parentData.vertical) {
|
||
this.translateX = 0
|
||
this.translateY = swiperItemLength * 100
|
||
} else {
|
||
this.translateX = swiperItemLength * 100
|
||
this.translateY = 0
|
||
}
|
||
}
|
||
// 正常情况
|
||
else {
|
||
if (this.parentData.vertical) {
|
||
this.translateX = 0
|
||
this.translateY = this.index * 100
|
||
} else {
|
||
this.translateX = this.index * 100
|
||
this.translateY = 0
|
||
}
|
||
}
|
||
},
|
||
// 更新父组件的偏移位置信息
|
||
updateParentSwiperContainerStyle(e) {
|
||
this.parent.updateSwiperContainerStyleWithValue(e.value)
|
||
},
|
||
// 根据方向更新父组件的偏移位置信息
|
||
updateParentSwiperContainerStyleWithDirection(e) {
|
||
this.parent.updateSwiperContainerStyleWithDirection(e.direction)
|
||
},
|
||
// 修改父组件的偏移位置的状态
|
||
changeParentSwiperContainerStyleStatus(e) {
|
||
// reset -> 重置 reload -> 重载
|
||
this.parent.updateSwiperContainerStyleWithDirection(e.status)
|
||
},
|
||
// 更新父组件信息
|
||
updateParentData() {
|
||
this.getParentData('tn-custom-swiper')
|
||
},
|
||
// 更新触摸状态
|
||
updateTouchingStatus(e) {
|
||
this.touching = e.status
|
||
if (e.status) {
|
||
this.parent.stopAutoPlay()
|
||
} else {
|
||
this.parent.startAutoPlay()
|
||
}
|
||
},
|
||
// 提取对应用户自定义样式
|
||
extractCustomStyle(customStyle) {
|
||
let data = {
|
||
transform: {},
|
||
style: {}
|
||
}
|
||
if (!customStyle) return data
|
||
// 允许设置的transform参数
|
||
const allowTransformProps = ['scale','scaleX','scaleY','scaleZ','rotate','rotateX','rotateY','rotateZ']
|
||
for (let prop in customStyle) {
|
||
if (prop.startsWith('transformProp')) {
|
||
// transform里面的样式
|
||
let transformProp = prop.substring('transformProp'.length)
|
||
const index = allowTransformProps.findIndex((item) => {
|
||
return item.toLowerCase() === transformProp.toLowerCase()
|
||
})
|
||
if (index !== -1) {
|
||
transformProp = allowTransformProps[index]
|
||
data.transform[transformProp] = customStyle[prop]
|
||
}
|
||
} else {
|
||
// 普通样式
|
||
data.style[prop] = customStyle[prop]
|
||
}
|
||
}
|
||
return data
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.tn-c-swiper-item {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: absolute;
|
||
display: block;
|
||
will-change: transform;
|
||
cursor: none;
|
||
transform: translate3d(0px, 0px, 0px);
|
||
|
||
.item__container {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
position: absolute;
|
||
}
|
||
}
|
||
</style>
|