前端利用touch相关的事件,实现可拖拽抽屉效果

333 阅读1分钟

xiezuo20240731-224252.gif

我们需要知道三个时机

  1. 手指按下 记录此时的位置 start
  2. 手指移动 计算当前位置距离初始位置滑动的距离 diff = current - start
  3. 手指松开 记录此时最终的滑动距离 diff_end = end -start

分别对应三个事件来处理

  1. touchstart
  2. touchmove
  3. touchend

我们监听元素的这三个事件,从event对象上拿到对应点的坐标:

监听touchstart 拿到初始位置start = e.touches[0].clientY,

监听touchmove实时计算 滑动的距离 diff = e.touches[0].clientY - start

监听touchend实时计算 滑动的距离 diff_end = 最新一次的diff

怎么实现跟手滑动?

利用transform 实现,实时更新diff 就好 :style="{ transform: 'translateY(' + diff + 'px)' }"

完整代码

<template>
  <div class="page">
    <div class="fixed-box" :style="{ transform: 'translateY(' + touch.diff + 'px)' }" v-if="showDrawer">
      <div class="touch-el" @touchstart="handleTouchStart" @touchend="handleTouchEnd" @touchmove="handleTouchMove">
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const showDrawer = ref(true)
// 抽屉盒子的高度
const MAX_HEIGHT = 400
const touch = ref({
  start: 0, // 手指按下的位置 Y轴坐标
  diff: 0 // 手指滑动的距离
})
// 手指按下,记录按下的位置
const handleTouchStart = (e) => {
  touch.value.start = e.touches[0].clientY
}
// 手指滑动,计算手指滑动的距离
const handleTouchMove = (e) => {
  const clientY = e.touches[0].clientY
  // 此处限制滑动距离>0,是为了限制抽屉上移超过起始位置
  touch.value.diff = clientY - touch.value.start < 0 ? 0 : clientY - touch.value.start
}
// 手指松开,判断滑动距离是否超过一半,超过一半则完全收起,否则回到初始位置
const handleTouchEnd = (e) => {
  if (touch.value.diff > MAX_HEIGHT / 2) {
    showDrawer.value = false
  } else {
    touch.value.diff = 0
  }
}

</script>
<style lang="less">
div{
  box-sizing: border-box;
  padding: 0;
  margin: 0
}
.page {
  background-color: skyblue;
  width: 100%;
  height: 100%;

  .fixed-box {
    position: fixed;
    border-top-right-radius: 15px;
    border-top-left-radius: 15px;
    bottom: 0;
    left: 0;
    width: 100%;
    background-color: pink;
    height: 400px;
    overflow: hidden;

    .touch-el {
      width: 100px;
      height: 30px;
      background-color: red;
      margin: 10px auto;
      border-radius: 15px;
    }
  }
}
</style>