新增
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<view class="chat-container">
|
||||
<view
|
||||
class="chat-container"
|
||||
@touchend.capture="onRecordingTouchEnd"
|
||||
@touchcancel.capture="onRecordingTouchCancel"
|
||||
>
|
||||
<!-- 顶部导航栏 -->
|
||||
<!-- 消息列表 -->
|
||||
<scroll-view
|
||||
@@ -126,8 +130,20 @@
|
||||
</view>
|
||||
|
||||
<!-- 录音浮层 - 微信风格 -->
|
||||
<view v-if="isRecording" class="recording-overlay">
|
||||
<view class="recording-popup" :class="{ 'recording-cancel': willCancel }">
|
||||
<view
|
||||
v-if="isRecording"
|
||||
class="recording-overlay"
|
||||
@click="forceCancelRecording"
|
||||
@touchend="onVoiceTouchEnd"
|
||||
@touchcancel="onVoiceTouchCancel"
|
||||
>
|
||||
<view
|
||||
class="recording-popup"
|
||||
:class="{ 'recording-cancel': willCancel }"
|
||||
@click.stop
|
||||
@touchend.stop="onVoiceTouchEnd"
|
||||
@touchcancel.stop="onVoiceTouchCancel"
|
||||
>
|
||||
<view class="recording-icon">
|
||||
<view v-if="!willCancel" class="recording-waves">
|
||||
<view class="wave"></view>
|
||||
@@ -183,6 +199,9 @@
|
||||
const isRecording = ref(false);
|
||||
const recordingDuration = ref(0);
|
||||
const willCancel = ref(false); // 上滑取消
|
||||
let voiceModeSwitchTime = 0; // 切换语音模式的时间戳,用于防误触
|
||||
let voiceHoldTimer = null; // 按住计时器,必须按住超过此时间才真正开始录音
|
||||
let isVoiceTouchDown = false; // 手指是否仍在按下
|
||||
const playingAudioId = ref('');
|
||||
let innerAudioContext = null;
|
||||
let chat = null;
|
||||
@@ -210,7 +229,27 @@
|
||||
|
||||
// 切换输入模式(文字/语音)
|
||||
function toggleInputMode() {
|
||||
inputMode.value = inputMode.value === 'text' ? 'voice' : 'text';
|
||||
const isSwitchToVoice = inputMode.value === 'text';
|
||||
inputMode.value = isSwitchToVoice ? 'voice' : 'text';
|
||||
// 切换到语音时:重置录音状态,防止卡住;记录时间用于防误触
|
||||
if (isSwitchToVoice) {
|
||||
isVoiceTouchDown = false;
|
||||
if (voiceHoldTimer) {
|
||||
clearTimeout(voiceHoldTimer);
|
||||
voiceHoldTimer = null;
|
||||
}
|
||||
isRecording.value = false;
|
||||
willCancel.value = false;
|
||||
recordingDuration.value = 0;
|
||||
if (recordingTimer) {
|
||||
clearInterval(recordingTimer);
|
||||
recordingTimer = null;
|
||||
}
|
||||
if (recorderManager) {
|
||||
try { recorderManager.stop(); } catch (_) {}
|
||||
}
|
||||
voiceModeSwitchTime = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化录音管理器
|
||||
@@ -239,14 +278,23 @@
|
||||
// #endif
|
||||
}
|
||||
|
||||
// 按住说话 - 开始
|
||||
// 按住说话 - 开始(必须按住超过 300ms 才真正开始录音,点击一下不会触发)
|
||||
function onVoiceTouchStart(e) {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 防误触:刚切换语音模式 400ms 内忽略触摸
|
||||
if (Date.now() - voiceModeSwitchTime < 400) return;
|
||||
e.preventDefault();
|
||||
isVoiceTouchDown = true;
|
||||
willCancel.value = false;
|
||||
touchStartY = e.touches[0]?.clientY || 0;
|
||||
if (!recorderManager) initRecorderManager();
|
||||
startRecord();
|
||||
// 必须按住 300ms 才真正开始录音,点击一下不会触发
|
||||
voiceHoldTimer = setTimeout(() => {
|
||||
voiceHoldTimer = null;
|
||||
if (isVoiceTouchDown) {
|
||||
startRecord();
|
||||
}
|
||||
}, 300);
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.showToast({ title: '当前平台暂不支持语音', icon: 'none' });
|
||||
@@ -257,6 +305,13 @@
|
||||
function onVoiceTouchEnd(e) {
|
||||
// #ifdef MP-WEIXIN
|
||||
e.preventDefault();
|
||||
isVoiceTouchDown = false;
|
||||
if (voiceHoldTimer) {
|
||||
clearTimeout(voiceHoldTimer);
|
||||
voiceHoldTimer = null;
|
||||
// 未按住满 300ms 就松开了,不开始录音
|
||||
return;
|
||||
}
|
||||
if (isRecording.value && recorderManager) {
|
||||
recorderManager.stop();
|
||||
}
|
||||
@@ -268,6 +323,40 @@
|
||||
onVoiceTouchEnd(e);
|
||||
}
|
||||
|
||||
// 捕获阶段监听:录音时任意位置松开都能结束(解决浮层遮挡导致 touchend 收不到的问题)
|
||||
function onRecordingTouchEnd(e) {
|
||||
if (isRecording.value) {
|
||||
e.stopPropagation();
|
||||
onVoiceTouchEnd(e);
|
||||
}
|
||||
}
|
||||
function onRecordingTouchCancel(e) {
|
||||
if (isRecording.value) {
|
||||
e.stopPropagation();
|
||||
onVoiceTouchCancel(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 强制取消录音(点击蒙层逃生,防止卡住)
|
||||
function forceCancelRecording() {
|
||||
isVoiceTouchDown = false;
|
||||
if (voiceHoldTimer) {
|
||||
clearTimeout(voiceHoldTimer);
|
||||
voiceHoldTimer = null;
|
||||
}
|
||||
if (!isRecording.value) return;
|
||||
willCancel.value = true;
|
||||
if (recorderManager) {
|
||||
try { recorderManager.stop(); } catch (_) {}
|
||||
}
|
||||
isRecording.value = false;
|
||||
recordingDuration.value = 0;
|
||||
if (recordingTimer) {
|
||||
clearInterval(recordingTimer);
|
||||
recordingTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
let touchStartY = 0;
|
||||
// 监听上滑取消
|
||||
function onVoiceTouchMove(e) {
|
||||
@@ -964,16 +1053,16 @@
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
font-weight: 500;
|
||||
background: #e0e0e0;
|
||||
|
||||
}
|
||||
|
||||
.avatar-in {
|
||||
background: #e0e0e0;
|
||||
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.avatar-out {
|
||||
background: #95ec69;
|
||||
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user