2022-10-26 11:14:13 +08:00

312 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
getStyleStr
} from '../../../utils/style.js';
// #ifdef APP-NVUE
const animation = uni.requireNativePlugin('animation')
// #endif
export default {
data() {
return {
timingFunction: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
isAnimated: false,
isScrolling: false,
customDuration: 0,
left: 0,
mCurrent: this.current
};
},
created() { },
mounted() {
// #ifdef MP
this.swiperViews = this.$children
// #endif
// #ifdef APP-PLUS || H5
// setTimeout(()=>{
// this.swiperViews = this.$slots.default.map(it => it.child)
// },1000)
this.swiperViews = this.$slots.default.map(it => it.child)
// #endif
this._setLeft();
this.mCurrent = this.current
this._notifyCurrentForItems(this.current, this.position)
},
watch: {
mCurrent() {
let current = this.mCurrent
if (this.circular) {
if (this.position == 1) {
current = this.actualSize - (this.plus - 1)
// console.log('最前了', current)
} else if (this.position == this._size - 2) {
current = this.plus - 2;
// console.log('最后了', current)
}
if (current < 0) {
current = this.position + 1
}
current %= this.actualSize
}
// console.log('position', this.position, current)
this.$emit('update:current', current)
this.$emit('change', current)
this._notifyCurrentForItems(current, this.position)
}
},
computed: {
is3D() {
return this.mode == '3d'
},
position() {
return this.circular ? (this.mCurrent + this.plus) : this.mCurrent
},
manualDuration() {
if (this.customDuration > 0)
return this.customDuration
return this.isAnimated ? this.duration : 0
},
boxStyle() {
return getStyleStr({
width: this.width + 'rpx',
height: this.height + 'rpx'
});
},
containerStyle() {
const style = {
height: this.height + 'rpx'
};
// #ifdef APP-NVUE
// FIXME: 理论isAnimated=false应该不设置transform,但是ios有个奇怪的问题top不为0导致布局错位
const isIOS = uni.getSystemInfoSync().platform == 'ios'
if (isIOS) {
style.transform = 'translate(' + uni.upx2px(this.left) + 'px' + ',0px)'
} else {
if (this.isAnimated == false) {
style.transform = 'translate(' + uni.upx2px(this.left) + 'px' + ',0px)'
}
}
// #endif
// #ifndef APP-NVUE
style.left = this.left+2 + 'rpx'
style.transition = 'left ' + this.manualDuration + 'ms ' + this.timingFunction
// #endif
return getStyleStr(style);
},
_size() {
return (this.$slots && this.$slots.default && this.$slots.default.length) || this.size;
},
// plus * 2
plusSize() {
return this.circular ? this.plus * 2 : 0;
},
// 真实长度
actualSize() {
return this._size - this.plusSize;
}
},
methods: {
prev() {
if (this.isAnimated) return;
if (this.isScrolling) return;
if (this.mCurrent == 0 && this.circular == false) return
this.mCurrent--;
this._run()
},
next() {
if (this.isAnimated) return;
if (this.isScrolling) return;
if (this.circular == true) {
this.mCurrent++;
if (this.mCurrent == this._size) {
this.mCurrent = 0;
}
} else {
if (this.mCurrent == this._size - 1) return
this.mCurrent++;
}
this._run()
},
moveTo(e) {
if (this.isAnimated) return
const {
deltaX,
left
} = e
this.isScrolling = true
if (!this.circular) {
if (
// 第一项,不能向右滑(上一项)
(deltaX > 0 && this.mCurrent == 0) ||
// 最后一项,不能向左滑(下一项)
(deltaX < 0 && this.mCurrent == this._size - 1)
) {
if (!this.bounce) return
// 添加阻尼滑动
const _left = this._left || this.wxsData.left
this.left = _left + (deltaX * (1 - Math.abs(deltaX) * 3 / (this.width * 5)))
this._set3DScale(deltaX)
return
}
}
this.left = left
// console.log(this.left);
this._set3DScale(deltaX)
},
moveEnd(e) {
const {
velocity,
deltaX,
deltaY
} = e
this.isScrolling = false
if (!this.circular) {
// 第一项,不能向右滑(上一项)
if (deltaX > 0 && this.mCurrent == 0) {
this._restoreStartTouch()
return
}
// 最后一项,不能向左滑(下一项)
if (deltaX < 0 && this.mCurrent == this._size - 1) {
this._restoreStartTouch()
return
}
}
const isTurnPage = Math.abs(deltaX) > this.itemWidth / 2
if (isTurnPage || velocity > 0.2) {
if (deltaX < 0) {
this.customDuration = 350
this.next()
} else if (deltaX > 0) {
this.customDuration = 350
this.prev()
}
} else {
this._restoreStartTouch()
}
},
_set3DScale(deltaX) {
if (this.is3D) {
const min = Math.min
const maxScale = Math.abs(this.scale - 1)
const mScale = deltaX * maxScale / this.width
const mRealScale = min(this.scale, this.scale - Math.abs(mScale))
this.swiperViews[this.position].mScale = mRealScale < 1 ? 1 : mRealScale
if (this.position - 1 > -1) {
this.swiperViews[this.position - 1].mScale = mScale > 0 ? min(this.scale, 1 + mScale) : min(1, 1 + mScale)
}
if (this.position + 1 < this._size) {
this.swiperViews[this.position + 1].mScale = mScale > 0 ? min(1, 1 - mScale) : min(this.scale, 1 - mScale)
}
}
},
_restoreStartTouch() {
const self = this
this.customDuration = 300
// #ifdef APP-VUE || MP-WEIXIN || H5
this.left = this.wxsData.left
// #endif
// #ifndef APP-PLUS || MP-WEIXIN || H5
this.left = this._left
// #endif
this._run(false)
if (this.is3D) {
this.swiperViews[this.position].restoreScale(this.manualDuration)
if (this.position - 1 > -1) {
this.swiperViews[this.position - 1].restoreScale(this.manualDuration)
}
if (this.position + 1 < this._size) {
this.swiperViews[this.position + 1].restoreScale(this.manualDuration)
}
}
},
_notifyCurrentForItems(current, position) {
this.swiperViews && this.swiperViews.forEach(it => {
it.current = current
it.position = position
})
},
_run(isSet = true) {
this.isAnimated = true;
if (isSet)
this._setLeft();
const self = this;
if (this.is3D) {
this.swiperViews[this.position].restoreToScale(this.scale, this.manualDuration)
if (this.position - 1 > -1) {
this.swiperViews[this.position - 1].restoreToScale(1, this.manualDuration)
}
if (this.position + 1 < this._size) {
this.swiperViews[this.position + 1].restoreToScale(1, this.manualDuration)
}
}
// #ifdef APP-NVUE
animation.transition(this.$refs.container, {
styles: {
transform: 'translate(' + uni.upx2px(this.left) + 'px' + ',0px)',
},
duration: this.manualDuration, //ms
timingFunction: this.timingFunction,
needLayout: false,
delay: 0 //ms
}, function () {
self._reset();
})
// #endif
// #ifndef APP-NVUE
setTimeout(() => {
this._reset();
}, this.manualDuration);
// #endif
},
_setLeft() {
if (this.circular == true) {
const s1 = (this.width - this.itemWidth - this.space * 2) / 2;
let left = (this.plus + this.mCurrent) * (this.space + this.itemWidth) - s1;
this.left = -left;
} else {
this.left = -(this.itemWidth + this.space) * this.mCurrent
}
// #ifdef APP-VUE || MP-WEIXIN || H5
this.wxsData = {
left: this.left,
bounce: this.bounce
}
// #endif
},
_reset() {
this.isScrolling = false
this.isAnimated = false
this.customDuration = 0
if (this.circular == true) {
if (this.position == 1) {
this.mCurrent = this.actualSize - (this.plus - 1);
this._setLeft();
this._restoreScale()
}
// -2原数组索引-1 + plus数组索引-1
if (this.position == this._size - 2) {
this.mCurrent = this.plus - 2;
this._setLeft();
this._restoreScale()
}
}
},
_restoreScale() {
if (this.is3D) {
this.swiperViews[this.position].restoreToScale(this.scale, 0)
if (this.position - 1 > -1) {
this.swiperViews[this.position - 1].restoreToScale(1, 0)
}
if (this.position + 1 < this._size) {
this.swiperViews[this.position + 1].restoreToScale(1, 0)
}
}
}
}
}