feat: 优化语音输入时的样式和输入框

This commit is contained in:
zhangyh
2025-10-17 17:09:33 +08:00
parent a856070570
commit 8994b4a1d2
4 changed files with 147 additions and 79 deletions

View File

@@ -21,18 +21,20 @@
<!-- 正常状态显示输入框 -->
<div class="input-wrapper">
<input
<textarea
id="textarea"
v-show="!isRecording"
v-model="inputValue"
type="text"
rows="1"
placeholder="Ask anything about your desired outfit"
class="text-input"
@keyup.enter="handleSend"
/>
@keydown="handleKeyDown"
@input="handleInput"
ref="textareaRef"
></textarea>
<div v-show="isRecording" class="recording-wrapper">
<!-- <div class="recording-animation"> -->
<AudioVisualizer />
<AudioVisualizer ref="audioVisualizerRef" />
<!-- </div> -->
</div>
</div>
@@ -51,13 +53,16 @@
</template>
<script setup lang="ts">
import { ref, onUnmounted } from 'vue'
import { ref, onUnmounted, nextTick } from 'vue'
import AudioVisualizer from './AudioVisualizer.vue'
import { showToast } from 'vant'
const emit = defineEmits(['send-message'])
const inputValue = ref<string>('')
const isRecording = ref<boolean>(false)
const audioVisualizerRef = ref<InstanceType<typeof AudioVisualizer> | null>(null)
const textareaRef = ref<HTMLTextAreaElement | null>(null)
const shortcutList: string[] = [
'Suggest shoe styles',
'Recommend evening bags',
@@ -72,6 +77,34 @@ const handleSend = (): void => {
console.log('input发送消息:', inputValue.value)
emit('send-message', inputValue.value)
inputValue.value = ''
// 重置textarea高度
if (textareaRef.value) {
textareaRef.value.style.height = 'auto'
}
}
}
// 处理键盘事件
const handleKeyDown = (event: KeyboardEvent): void => {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault()
handleSend()
}
}
// 处理输入事件,自动调整高度
const handleInput = (): void => {
if (textareaRef.value) {
textareaRef.value.style.height = 'auto'
// const lineHeight = 4.8
// const maxLines = 3
// const maxHeight = lineHeight * maxLines
const scrollHeight = textareaRef.value.scrollHeight
// const newHeight = Math.min(scrollHeight, maxHeight * 10)
textareaRef.value.style.height = `${scrollHeight}px`
}
}
@@ -89,9 +122,24 @@ onUnmounted(() => {
}
})
const handleClickAudio = (): void => {
const handleClickAudio = async (): Promise<void> => {
isRecording.value = !isRecording.value
// 当开始录音时等待DOM更新后触发AudioVisualizer重新计算
if (isRecording.value) {
await nextTick()
// 立即尝试更新
if (audioVisualizerRef.value) {
audioVisualizerRef.value.updateLines?.()
}
// 快速重试
setTimeout(() => {
if (audioVisualizerRef.value) {
audioVisualizerRef.value.updateLines?.()
}
}, 50)
}
if (isRecording.value) {
startRecording()
} else {
@@ -168,7 +216,8 @@ const startRecording = () => {
speechRecognition.onerror = (event) => {
console.error('语音识别错误:', event.error)
isRecording.value = false
alert('语音识别失败,请重试')
// alert('语音识别失败,请重试')
showToast(event.error)
}
// 开始识别
@@ -215,8 +264,8 @@ const stopRecording = () => {
display: flex;
align-items: center;
background-color: #efefef;
padding: 0 4.85rem 0 5.2rem;
height: 19.3rem;
padding: 1.5rem 4.85rem 1.5rem 5.2rem;
min-height: 19.3rem;
}
.icon-wrapper {
@@ -236,6 +285,7 @@ const stopRecording = () => {
margin-left: 5.59rem;
margin-right: 3.5rem;
background-color: #888;
align-self: center;
}
.input-wrapper {
@@ -243,26 +293,22 @@ const stopRecording = () => {
display: flex;
align-items: center;
overflow: hidden;
// height: 100%;
}
.text-input {
width: 100%;
// height: 100%;
height: auto;
// min-height: 4.8rem;
// max-height: 100%;
max-height: 14.4rem;
border: none;
outline: none;
background: transparent;
font-size: 4rem;
font-family: 'robotoBold';
font-weight: 400;
line-height: 121%;
// padding-right: 2rem;
margin-right: 4.21rem;
line-height: 4.8rem; /* 设置行高等于实际渲染高度,实现垂直居中 */
padding: 0;
color: #000;
// resize: none;
word-break: break-all;
&::placeholder {
color: #888;
@@ -288,6 +334,7 @@ const stopRecording = () => {
flex: 1;
display: flex;
align-items: center;
min-height: 4.8rem;
}
.recording-animation {