特殊按钮:长按触发 / 长按松开触发

166 阅读2分钟

vue2工程

长按触发

<template>
    <div>
        <button class="floating-btn" @touchstart="startLongPress" @touchmove="stopLongPress" @touchend="stopLongPress">
            <van-icon name="aim" size="40" />
        </button>
    </div>
</template>
<script>
export default {
    name: 'App',
    data() {
        return {
          longPressTimeout: null,
          pressDuration: 1000, // 设置长按时间阈值为 1000 毫秒(1秒)
          isPressing: false
        };
      },
    mounted() {
        
    },
    methods: {
        startLongPress() {
            console.log("______1111");
            // 清除任何已有的长按计时器(防止连续点击)
            if (this.longPressTimeout) {
                clearTimeout(this.longPressTimeout);
            }

            // 设定计时器
            this.longPressTimeout = setTimeout(() => {
                this.isPressing = true;
                this.onLongPress();
            }, this.pressDuration);
        },
        stopLongPress() {
            console.log("______2222");

            // 如果长按时间小于设定阈值,取消触发长按事件
            if (this.longPressTimeout) {
                clearTimeout(this.longPressTimeout);
                this.longPressTimeout = null;
            }

            // 如果按下时间不到阈值,说明不是长按
            if (this.isPressing) {
                this.isPressing = false;
            }
        },
        onLongPress() {
            console.log("______333");

            // 处理长按事件
            alert("长按触发!");
        }
    }
}
</script>
<style lang="scss">
.floating-btn {
    width: 50px;
    height: 50px;
    position: fixed;
    bottom: 130px;
    right: 20px;
    background-color: transparent;
    color: white;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.2);
    z-index: 9999999;
    background-color: #7289e6;
    display: flex;
    align-items: center;
    justify-content: center;
}

// .floating-btn:hover {
//     background-color: #ff80b5;
// }
</style>

长按松开触发,效果如下 image.png

<template>
    <div :class="[{ 'voiceview': voicestart }]">
        <div class="speak-content">
            <Typing v-if="voicestart" style="z-index: 99999;"/>
        </div>
        <div class="speak-btn">
            <div class="tip" v-if="voicestart && !isOverTarget">松开 发送</div>
            <div class='btn' @touchstart="startLongPress" @touchend="stopLongPress" @touchmove="touchmove">
                按住说话
            </div>
        </div>
        <div class="delete-btn" v-if="voicestart">
            <div class="tip" v-if="isOverTarget">松开 取消发送</div>
            <div class='btn' ref="targetArea">
                拉到这里松开取消
            </div>
        </div>
    </div>
</template>
<script>
import Typing from './Typing.vue';
export default {
    name: 'App',
    data() {
        return {
            voicestart: false,
            longPressTimer: null,
            isOverTarget: false,  // 判断是否进入目标区域
            startX: 0,           // 记录触摸开始时的X坐标
            startY: 0,           // 记录触摸开始时的Y坐标
            Typingshow:false
        };
    },
    components: {
        Typing
    },
    mounted() {

    },
    methods: {
        startLongPress(event) {
            this.longPressTimer = setTimeout(() => {
                this.voicestart = true;
                const touch = event.touches[0];  // 获取触摸点
                this.startX = touch.clientX;
                this.startY = touch.clientY;
                this.isOverTarget = false;  // 重置进入目标区域的状态
                setTimeout(() => {
                    this.Typingshow=true;
                }, 1500);
            }, 500);
        },
        stopLongPress() {
            console.log("发送语音或者取消语音");
            if (this.isOverTarget) {
                console.log("取消语音");
                this.Typingshow=false;
            } else {
                console.log("发送语音");
            }
            this.isOverTarget = false; // 触摸结束时清除状态
            clearTimeout(this.longPressTimer);
            this.voicestart = false;
        },
        touchmove(event) {
            const touch = event.touches[0];  // 获取触摸点
            const touchX = touch.clientX;
            const touchY = touch.clientY;

            // 获取目标元素的位置信息
            const targetRect = this.$refs.targetArea.getBoundingClientRect();

            // 判断触摸点是否在目标区域内
            const isInsideTarget =
                touchX >= targetRect.left &&
                touchX <= targetRect.right &&
                touchY >= targetRect.top &&
                touchY <= targetRect.bottom;

            this.isOverTarget = isInsideTarget;
        }
    }
}
</script>
<style lang="scss">
.speak-btn {
    position: fixed;
    bottom: 130px;
    right: 20px;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    align-items: end;

    .tip {
        color: white;
        font-size: 16px;
    }

    .btn {
        margin-top: 20px;
        width: 50px;
        height: 50px;
        background-color: transparent;
        color: white;
        border: none;
        border-radius: 50%;
        cursor: pointer;
        box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.2);
        background-color: #7289e6;
        display: flex;
        align-items: center;
        justify-content: center;
    }
}

.delete-btn {
    position: fixed;
    bottom: 130px;
    left: 20px;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    align-items: start;

    .tip {
        color: white;
        font-size: 16px;
    }

    .btn {
        font-size: 16px;
        margin-top: 20px;
        width: 50px;
        height: 50px;
        background-color: transparent;
        color: white;
        border: none;
        border-radius: 50%;
        cursor: pointer;
        box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.2);
        background-color: #e34d4d;
        display: flex;
        align-items: center;
        justify-content: center;
    }
}

.speak-content{
    position: fixed;
    top: 50%;
    transform: translateY(-50%);
    padding: 20px;
    margin-top: -120px;
}

// .speak-btn:hover {
//     background-color: #ff80b5;
// }
.voiceview {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.85);
    display: flex;
    // justify-content: center;
    align-items: center;
    flex-direction: column;
    z-index: 9999;
}
</style>