Files
medicine_app/components/player/Gesture.nvue
2024-06-19 16:12:23 +08:00

216 lines
4.8 KiB
Plaintext

<template>
<view
@touchstart.stop="touchstart"
@touchmove.stop="touchmove"
@touchend.stop="touchend">
<slot></slot>
</view>
</template>
<script>
export default {
props: {
holeWidth: Number, // 屏幕宽度(物理像素)
duration: Number, // 视频总时长
currentTime: Number // 视频当前播放时间
},
computed: {
halfWidth() {
return parseInt(this.holeWidth / 2);
}
},
data() {
return {
downLeft: false, // 是否在左区域按下手势
swipeDir: null // 滑动方向
}
},
mounted() {
this.addHandler();
},
methods:{
addHandler() {
// 增加父容器左右滑动监听
let finalTime = -1;
// 计算左右滑动seek进度
const countTime = (position) => {
const { holeWidth, duration, currentTime } = this;
const precent = Math.abs(position) / holeWidth;
const nowTime = currentTime || 0;
let plusTime = parseInt(Math.abs(precent * duration));
if (position < 0) plusTime = plusTime * -1;
finalTime = nowTime + plusTime;
finalTime = this.limit(finalTime, 0, duration);
return finalTime;
};
this.addGesture((type, position) => {
switch (type) {
// 下滑
case -1:
this.$emit('onGestureEvent', {
type: this.downLeft ? 'LEFT_DOWN' : 'RIGHT_DOWN',
position
});
break;
// 上滑
case -2:
this.$emit('onGestureEvent', {
type: this.downLeft ? 'LEFT_UP' : 'RIGHT_UP',
position
});
break;
// 左滑
case 0:
this.swipeDir = type;
countTime(position);
this.$emit('onGestureEvent', {
type: 'SEEK_TIME_UPDATE',
finalTime
});
break;
// 右滑
case 1:
this.swipeDir = type;
countTime(position);
this.$emit('onGestureEvent', {
type: 'SEEK_TIME_UPDATE',
finalTime
});
break;
// touchend for swipe
case 3:
if (this.swipeDir > -1) {
this.$emit('onGestureEvent', {
type: this.swipeDir ? 'SWIPE_RIGHT' : 'SWIPE_LEFT'
});
this.swipeDir = -1;
}
if (finalTime > -1) {
this.$emit('onGestureSeekTo', finalTime);
finalTime = -1;
}
this.$emit('onGestureEvent', {
type: 'TOUCH_END'
});
break;
// doubleTap
case 4:
break;
// tap
case 5:
this.handleClick();
break;
// longTap
case 6:
break;
}
});
},
addGesture(callback) {
const { options } = this;
let startX, startY, moveEndX, moveEndY, X, Y, position, hasType;
let T, lastTap, isJustTouch = true;
const excuteCb = (type) => {
// type 手势类型 -2 上滑 -1 下滑 0 左滑 1 右滑 2 just touch 3 touchend 4 doubleTap 5 tap 6 longTap
if (callback && typeof callback === 'function')
callback(type, position);
};
const isXchange = () => {
if (Math.abs(X) > Math.abs(Y)) {
position = X;
hasType = 'X';
isJustTouch = false;
}
if (X >= 0) excuteCb(1);
// 左滑
else excuteCb(0);
};
const isYchange = () => {
if (Math.abs(Y) > Math.abs(X)) {
position = Y;
hasType = 'Y';
isJustTouch = false;
}
if (Y >= 0) excuteCb(-1);
// 上滑
else excuteCb(-2);
};
const countDirect = () => {
if (hasType) {
hasType === 'X' ? isXchange() : isYchange();
return;
}
if (Math.abs(X) > 5) {
isXchange();
return;
}
if (Math.abs(Y) > 5) {
isYchange();
}
};
this.handleTouch = (type, e) => {
switch(type) {
case 'start':
startX = e.touches[0].screenX;
startY = e.touches[0].screenY;
T = Date.now();
hasType = '';
isJustTouch = true;
this.downLeft = startX < this.halfWidth ? true : false;
break;
case 'move':
moveEndX = e.touches[0].screenX;
moveEndY = e.touches[0].screenY;
X = moveEndX - startX;
Y = moveEndY - startY;
// console.log('Y', Y);
countDirect();
break;
case 'end':
if (isJustTouch)
if (lastTap && Date.now() - lastTap <= 300)
excuteCb(4);
else if (Date.now() - T < 1000)
excuteCb(5);
else
excuteCb(6);
else
excuteCb(3);
lastTap = Date.now();
isJustTouch = true;
break;
}
};
},
handleClick() {
this.$emit('onGestureClick');
},
touchstart(e) {
this.handleTouch('start', e);
},
touchmove(e) {
this.handleTouch('move', e);
},
touchend(e) {
this.handleTouch('end', e);
},
limit(num, min, max) {
if (num < min) return min;
if (num > max) return max;
return num;
}
}
}
</script>
<style></style>