312 lines
8.0 KiB
JavaScript
312 lines
8.0 KiB
JavaScript
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)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|