这个函数接受一个 HTMLElement 的 Ref 作为参数,以及一个可选的 Options 参数,Options 参数包含了各种事件钩子,可以在滑动过程中执行阻止默认事件的操作。
在函数中,主要做了以下事情:
- 使用
ref来创建跟踪滑动起点、终点、是否正在滑动等状态的变量。 - 使用
computed来计算滑动的距离(x 和 y 方向上的变化)以及滑动的方向(left、right、up、down)。 - 定义了
onStart、onMove和onEnd函数,分别处理滑动开始、滑动过程和滑动结束的逻辑,并在这些函数中调用了用户提供的事件钩子(beforeStart、afterStart 等)。 - 在组件挂载时(
onMounted)添加了滑动事件监听器,并在组件卸载时(onUnmounted)移除了这些监听器,以确保事件处理不会发生内存泄漏。
最后,函数返回了 swiping(是否正在滑动)、direction(滑动方向)和 distance(滑动距离)等值,在Vue组件中使用。
import { computed, onMounted, onUnmounted, ref, Ref } from "vue";
type Point = {
x: number;
y: number;
}
interface Options{
beforeStart?:(e:TouchEvent)=>void
afterStart?:(e:TouchEvent)=>void
beforeMove?:(e:TouchEvent)=>void
afterMove?:(e:TouchEvent)=>void
beforeEnd?:(e:TouchEvent)=>void
afterEnd?:(e:TouchEvent)=>void
}
export const useSwipe = (element: Ref< HTMLElement | undefined>,options?:Options) => {
const start = ref<Point>()
const end = ref<Point>()
const swiping = ref(false)
const distance = computed(() => {
if (!start.value || !end.value) { return null }
return {
x: end.value.x - start.value.x,
y: end.value.y - start.value.y,
}
})
const direction = computed(() => {
if (!distance.value) { return '' }
const { x, y } = distance.value
if (Math.abs(x) > Math.abs(y)) {
return x > 0 ? 'right' : 'left'
} else {
return y > 0 ? 'down' : 'up'
}
})
const onStart = (e: TouchEvent) => {
options?.beforeStart?.(e)
e.preventDefault()
swiping.value = true
end.value = start.value = { x: e.touches[0].screenX, y: e.touches[0].screenY }
options?.afterStart?.(e)
}
const onMove = (e: TouchEvent) => {
options?.beforeMove?.(e)
if (!start.value) { return }
end.value = { x: e.touches[0].screenX, y: e.touches[0].screenY, }
options?.afterMove?.(e)
}
const onEnd = (e: TouchEvent) => {
options?.beforeEnd?.(e)
swiping.value = false
options?.afterEnd?.(e)
}
onMounted(() => {
if (!element.value) { return }
element.value.addEventListener('touchstart', onStart)
element.value.addEventListener('touchmove', onMove)
element.value.addEventListener('touchend', onEnd)
})
onUnmounted(() => {
if (!element.value) { return }
element.value.removeEventListener('touchstart', onStart)
element.value.removeEventListener('touchmove', onMove)
element.value.removeEventListener('touchend', onEnd)
})
return {
swiping,
direction,
distance,
}
}