小程序按住说话、上滑取消的实现。
使用view作为容器总有奇怪的问题,比如touchend
事件有时候不触发。
需要使用事件修饰符来阻止冒泡,不如有时候touchend、touchmove
也不会触发。
下面是效果及源码。
<template>
<view class="w-full bg-white">
<button
class="record-btn w-full"
style="padding: 0; line-height: 22px; background-color: transparent"
@touchend.stop="handleTouchEnd"
@touchmove.stop="handleTouchmove"
@longpress.stop="handleLongPress"
>
<view v-if="isRecording">
<view class="text-center text-secondary text-xs py-3">
<text v-if="isUp">松开取消</text>
<text v-else>松手发送,上滑取消</text>
</view>
<Wave :bgColor="`var(--wot-color-${isUp ? 'danger' : 'theme'})`" />
</view>
<view v-else class="leading-22px py-3">
<view>
<text class="font-bold">按住说话</text>
</view>
</view>
</button>
</view>
</template>
<script lang="ts" setup>
import Wave from './Wave.vue'
const isRecording = ref(false) // 状态,当前是否在录音
const isUp = ref(false) // 是否上滑
const startY = ref(0)
const handleLongPress = (event) => {
startY.value = event.touches[0].clientY
isRecording.value = true
console.log(`output->按压的坐标`, startY.value)
}
const handleTouchEnd = () => {
isRecording.value = false
startY.value = 0
isUp.value = false
console.log(`output->离开后的坐标`, startY.value)
}
const handleTouchmove = (event) => {
if (!isRecording.value) return
const currentY = event.touches[0].clientY
const diffY = startY.value - currentY
// 设定阈值,防止误判
isUp.value = diffY > 10
}
</script>
wave.vue
<template>
<view
class="wave-container"
:style="{
'background-color': bgColor,
}"
>
<view :class="`wave-bar wave-bar-delay-${n}`" v-for="n in generateSequence(20)" :key="n"></view>
</view>
</template>
<script lang="ts" setup>
type PropsType = { bgColor: string }
const props = defineProps<PropsType>()
function generateSequence(n) {
const result = []
// 递增部分:1 到 n
for (let i = 1; i <= n; i++) {
result.push(i)
}
// 递减部分:n-1 到 1
for (let i = n - 1; i >= 1; i--) {
result.push(i)
}
return result
}
</script>
<style lang="scss" scoped>
$number: 20;
.wave-container {
display: flex;
gap: 5px;
align-items: center;
justify-content: center;
width: 100%;
height: 22px;
padding: 12px 0;
border-radius: 10px;
}
.wave-bar {
width: 3px;
height: 10px;
background-color: #fff;
border-radius: 2px;
animation: wave 1s infinite ease-in-out;
}
@for $i from 1 through $number {
.wave-bar-delay-#{$i} {
animation-delay: $i * -0.8 + s;
}
}
@keyframes wave {
0%,
100% {
transform: scaleY(0.8);
}
50% {
transform: scaleY(1);
}
}
</style>