mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
147 lines
3.3 KiB
Vue
147 lines
3.3 KiB
Vue
<template>
|
|
<div
|
|
v-clickoutside:touchstart="onClick"
|
|
class="van-cell-swipe"
|
|
@click="onClick('cell')"
|
|
@touchstart="startDrag"
|
|
@touchmove="onDrag"
|
|
@touchend="endDrag"
|
|
@touchcancel="endDrag"
|
|
>
|
|
<div class="van-cell-swipe__wrapper" :style="wrapperStyle" @transitionend="swipe = false">
|
|
<div class="van-cell-swipe__left" @click.stop="onClick('left')" v-if="leftWidth">
|
|
<slot name="left" />
|
|
</div>
|
|
<slot />
|
|
<div class="van-cell-swipe__right" @click.stop="onClick('right')" v-if="rightWidth">
|
|
<slot name="right" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { create } from '../utils';
|
|
import Clickoutside from '../utils/clickoutside';
|
|
|
|
const THRESHOLD = 0.15;
|
|
|
|
export default create({
|
|
name: 'van-cell-swipe',
|
|
|
|
props: {
|
|
onClose: Function,
|
|
leftWidth: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
rightWidth: {
|
|
type: Number,
|
|
default: 0
|
|
}
|
|
},
|
|
|
|
directives: {
|
|
Clickoutside
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
offset: 0,
|
|
draging: false
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
wrapperStyle() {
|
|
return {
|
|
transform: `translate3d(${this.offset}px, 0, 0)`,
|
|
transition: this.draging ? 'none' : '.6s cubic-bezier(0.18, 0.89, 0.32, 1)'
|
|
};
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
close() {
|
|
this.offset = 0;
|
|
},
|
|
|
|
resetSwipeStatus() {
|
|
this.swiping = false;
|
|
this.opened = true;
|
|
},
|
|
|
|
swipeMove(offset = 0) {
|
|
this.offset = offset;
|
|
offset && (this.swiping = true);
|
|
!offset && (this.opened = false);
|
|
},
|
|
|
|
swipeLeaveTransition(direction) {
|
|
const { offset, leftWidth, rightWidth } = this;
|
|
const threshold = this.opened ? (1 - THRESHOLD) : THRESHOLD;
|
|
|
|
// right
|
|
if (direction > 0 && -offset > rightWidth * threshold && rightWidth > 0) {
|
|
this.swipeMove(-rightWidth);
|
|
this.resetSwipeStatus();
|
|
// left
|
|
} else if (direction < 0 && offset > leftWidth * threshold && leftWidth > 0) {
|
|
this.swipeMove(leftWidth);
|
|
this.resetSwipeStatus();
|
|
} else {
|
|
this.swipeMove();
|
|
}
|
|
},
|
|
|
|
startDrag(event) {
|
|
this.draging = true;
|
|
this.startX = event.touches[0].pageX;
|
|
this.startY = event.touches[0].pageY;
|
|
|
|
if (this.opened) {
|
|
this.startX -= this.offset;
|
|
}
|
|
},
|
|
|
|
onDrag(event) {
|
|
const offsetTop = event.touches[0].pageY - this.startY;
|
|
const offsetLeft = event.touches[0].pageX - this.startX;
|
|
if ((offsetLeft < 0 && -offsetLeft > this.rightWidth) ||
|
|
(offsetLeft > 0 && offsetLeft > this.leftWidth) ||
|
|
(offsetLeft > 0 && !this.leftWidth) ||
|
|
(offsetLeft < 0 && !this.rightWidth)) {
|
|
return;
|
|
}
|
|
|
|
const y = Math.abs(offsetTop);
|
|
const x = Math.abs(offsetLeft);
|
|
const swiping = !(x < 5 || (x >= 5 && y >= x * 1.73));
|
|
if (swiping) {
|
|
event.preventDefault();
|
|
this.swipeMove(offsetLeft);
|
|
};
|
|
},
|
|
|
|
endDrag() {
|
|
this.draging = false;
|
|
if (this.swiping) {
|
|
this.swipeLeaveTransition(this.offset > 0 ? -1 : 1);
|
|
};
|
|
},
|
|
|
|
onClick(position = 'outside') {
|
|
if (!this.offset) {
|
|
return;
|
|
}
|
|
|
|
if (this.onClose) {
|
|
this.onClose(position, this);
|
|
} else {
|
|
this.swipeMove(0);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
</script>
|