我们需要知道三个时机
- 手指按下 记录此时的位置 start
- 手指移动 计算当前位置距离初始位置滑动的距离 diff = current - start
- 手指松开 记录此时最终的滑动距离 diff_end = end -start
分别对应三个事件来处理
- touchstart
- touchmove
- 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>