yaoningvital / blog

my blog
31 stars 4 forks source link

touch事件的应用 #196

Open yaoningvital opened 4 years ago

yaoningvital commented 4 years ago

一、问题场景

今天写一个叫“华容道”的项目,里面的方块在滑动时,有可能向“上下左右”四个方向移动,所以普通的click事件不能满足,只能通过touch事件来判断手指是向哪个方向滑动的,方块应该往哪个方向移动。

二、分析

1、touch事件的类型

touch 事件有下面几种:

在这个项目中,我只用到了:

2、分析思路

(1)为滑块绑定 touchStart 事件,当手指放上去,就会触发 touchStart;只会触发一次;

(2)此时在 event.targetTouches 中会记录手指触摸的点的数据。 event.targetTouches[0]是第一根手指的数据; event.targetTouches[0].pageX 是第一根手指触摸点的 X 坐标的值; event.targetTouches[0].pageY 是第一根手指触摸点的 Y 坐标的值; 将这个开始位置记录下来,记录为 startPos。

(3)为滑块绑定 touchMove 事件,当手指移动时,就会触发 touchMove;

(4)此时在 event.targetTouches 中会记录手指移动时触摸点的数据。 event.targetTouches[0]是第一根手指的数据; event.targetTouches[0].pageX 是第一根手指触摸点移动到的 X 坐标的值; event.targetTouches[0].pageY 是第一根手指触摸点移动到的 Y 坐标的值; 将这个开始位置记录下来,记录为 moveToPos。

(5)滑动过程中会触发多次 touchMove 事件,每次触发时都执行第(4)步中的操作,moveToPos 的值将会被不断更新,确保里面存的是最后位置的数据。

(6)为滑块绑定 touchEnd 事件,当手指离开时,就会触发 touchEnd;只会触发一次;需要在这个事件中做一系列的判断,来判断滑块应该往哪个方向移动(moveDirection)。

// xDistance 为在x轴方向移动的距离
  let xDistance = startPos.pageX - moveToPos.pageX

// yDistance 为在y轴方向移动的距离
  let yDistance = startPos.pageY - moveToPos.pageY

// 如果在x轴方向移动的距离 大于 在y轴方向移动的距离,则认为手指滑动的方向是 水平方向
// 反之,则认为手指滑动方向是 垂直方向
  moveAxis = Math.abs(xDistance) > Math.abs(yDistance) ? 'horizontal' : 'vertical' // 手指滑动的方向(水平方向 or 垂直方向)

  if (moveAxis === 'horizontal') { // 水平方向滑动
    if (xDistance < -10) { // 往右移
      // console.log('往右移')
      moveDirection = 'right'
    } else if (xDistance > 10) { // 往左移
      // console.log('往左移')
      moveDirection = 'left'
    }
  } else if (moveAxis === 'vertical') { // 垂直方向移动
    // console.log('yDistance:', yDistance)
    if (yDistance < -10) { // 往下移
      // console.log('往下移')
      moveDirection = 'bottom'
    } else if (yDistance > 10) { // 往上移
      // console.log('往上移')
      moveDirection = 'top'
    }
  }

这样就能判断手指滑动方向是“上下左右”了。

三、完整代码

function handleTouchStart (dispatch, e, isShowHowing) {
  if (isShowHowing) return
  let startPos = {
    pageX: e.targetTouches[0].pageX,
    pageY: e.targetTouches[0].pageY,
  }
  dispatch(setStartPos(startPos))

}

function handleTouchMove (dispatch, e, isShowHowing) {
  if (isShowHowing) return
  e.preventDefault()
  let moveToPos = {
    pageX: e.targetTouches[0].pageX,
    pageY: e.targetTouches[0].pageY,
  }
  dispatch(setMoveToPos(moveToPos))

}

function handleTouchEnd (dispatch, e, {name, id, startPos, moveToPos, layout, isShowHowing}) {
  if (isShowHowing) return
  let moveAxis = null
  let moveDirection = null
  let xDistance = startPos.pageX - moveToPos.pageX
  let yDistance = startPos.pageY - moveToPos.pageY
  moveAxis = Math.abs(xDistance) > Math.abs(yDistance) ? 'horizontal' : 'vertical' // 手指滑动的方向(水平方向 or 垂直方向)

  if (moveAxis === 'horizontal') { // 水平方向滑动
    if (xDistance < -10) { // 往右移
      // console.log('往右移')
      moveDirection = 'right'
    } else if (xDistance > 10) { // 往左移
      // console.log('往左移')
      moveDirection = 'left'
    }
  } else if (moveAxis === 'vertical') { // 垂直方向移动
    // console.log('yDistance:', yDistance)
    if (yDistance < -10) { // 往下移
      // console.log('往下移')
      moveDirection = 'bottom'
    } else if (yDistance > 10) { // 往上移
      // console.log('往上移')
      moveDirection = 'top'
    }
  }

  if (moveDirection) {
    let newLayout = updateLayout(dispatch, layout, name, id, moveDirection)
    if (hasSucceed(newLayout)) {
      dispatch(setSuccessful(true))
    }
  }
}