自定义手势判断在日历上的应用
在移动端,通常日历展示为当前月的日期纪录,当切换月份的过程中,需要通过手势左滑或者右滑进行月份切换,以下说明如何自行完成一个滑动的手势判断以及逻辑处理
这里借助Vue的自定义指令进行代码阐述,SELECTWRAP_DOM为绑定的DOM元素
bind(el, binding, vnode) {
var startX = 0
var startY = 0
var endX = 0
var endY = 0
const SELECTWRAP_DOM = el
var judgeX = 0
var judgeY = 0
var lockY = false
SELECTWRAP_DOM.addEventListener('touchstart', (event) => {
// 监听滑动开始,细节见下方
}
SELECTWRAP_DOM.addEventListener('touchmove', (event) => {
// 监听滑动,细节见下方
}
SELECTWRAP_DOM.addEventListener('touchend', (event) => {
// 监听滑动结束,细节见下方
}
}
- 首先获取到dom元素之后,对其绑定touchstart事件,也就作为手势判断的起点
SELECTWRAP_DOM.addEventListener('touchstart', (event) => {
var touch = event.touches[0]
// 获取当前触控点起点的坐标,包含X,Y
startX = touch.pageX
startY = touch.pageY
})
- 然后对dom监听touchmove事件,但是此事件只获取起始的第一个点,作为手势判断的终点
SELECTWRAP_DOM.addEventListener('touchmove', (event) => {
var touch = event.targetTouches[0]
// 手势滑动时,手势坐标不断变化,取最后一点 的坐标为最终的终点坐标
endX = touch.pageX
endY = touch.pageY
// 这里纪录拖动之后的第一个点,在拖动过程中只纪录一次
if (judgeX == 0 && judgeY == 0) {
judgeX = endX
judgeY = endY
}
let Ylength = Math.abs(judgeY - startY)
let Xlength = Math.abs(judgeX - startX)
// 根据等边三角形计算角度关系
lockY = Ylength / Xlength < 1
if (lockY) {
// 屏蔽Y轴滑动
event.preventDefault()
// 执行X轴滑动动画
SELECTWRAP_DOM.style.transform = `translateX(${endX - startX}px)`
}
// 如果没有判定为X轴滑动,即不会执行动画,只能上下拖动
})
- 最后监听touchend事件,对判断数据进行重置以及其他处理
SELECTWRAP_DOM.addEventListener('touchend', (event) => {
var distanceX = endX - startX
// 将拖动效果还原,偏移归0
SELECTWRAP_DOM.style.transform = `translateX(0px)`
/* 如果当前偏移存在,且偏移量>50,因为小的偏移量可能是用户误操作造成,并且起点和终点的X轴都发生了变化,有可能用户只是点了一下
那么endX必为0,disctance计算出来就会产生偏移,所以排除此情况,执行自定义指令函数
*/
// 如果X轴滑动了,执行命令,否则即清空数据,供下次滑动检测
if (distanceX != 0 && (Math.abs(distanceX) > 50 && lockY) && startX != 0 && endX != 0) binding.value(distanceX)
// 将缓存的坐标点还原,供下次使用
startX = 0
startY = 0
endX = 0
endY = 0
judgeX = 0
judgeY = 0
lockY = false
})
结论:在比值判断之前采取的是固定数值判断,缺点在于不同屏幕下,会存在误判的可能,或者Y轴敏感,或者X轴敏感,体验感都不好。最终采用比值关系之后,效果显著提升。