Files
YGChatCS/components/Speech/RecordingWaveBtn.vue
2025-08-10 19:40:47 +08:00

129 lines
2.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="recording-wave-btn">
<view class="audio-visualizer">
<view
v-for="(bar, index) in audioBars"
:key="index"
class="audio-bar"
:style="{
height: bar.height + 'px',
transition: 'height 0.1s ease-out',
}"
></view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
const animationTimer = ref(null);
const isAnimating = ref(false);
// 音频条数据
const audioBars = ref([]);
const BAR_COUNT = 30;
// 初始化音频条
const initAudioBars = () => {
audioBars.value = [];
for (let i = 0; i < BAR_COUNT; i++) {
audioBars.value.push({
height: 4 + Math.random() * 8,
});
}
};
// 更新音频条动画
const updateAudioBars = () => {
if (!isAnimating.value) return;
// 使用 for 循环随机修改每个音频条的高度
for (let i = 0; i < audioBars.value.length; i++) {
const bar = audioBars.value[i];
// 生成随机高度值
const minHeight = 4;
const maxHeight = 20;
const randomHeight = minHeight + Math.random() * (maxHeight - minHeight);
// 添加一些变化幅度,让高度变化更自然
const variation = (Math.random() - 0.5) * 10;
bar.height = Math.max(
minHeight,
Math.min(maxHeight, randomHeight + variation)
);
}
};
// 开始动画
const startAnimation = () => {
if (!isAnimating.value) {
isAnimating.value = true;
const animate = () => {
if (isAnimating.value) {
updateAudioBars();
animationTimer.value = setTimeout(animate, 200); // 每200ms更新一次模仿人类说话语速
}
};
animate();
}
};
// 停止动画
const stopAnimation = () => {
isAnimating.value = false;
if (animationTimer.value) {
clearTimeout(animationTimer.value);
animationTimer.value = null;
}
};
// 组件挂载时初始化并自动开始动画
onMounted(() => {
initAudioBars();
startAnimation();
});
// 组件卸载时停止动画
onUnmounted(() => {
stopAnimation();
});
// 暴露方法给父组件
defineExpose({
startAnimation,
stopAnimation,
});
</script>
<style scoped lang="scss">
.recording-wave-btn {
box-shadow: 0px 0px 20px 0px rgba(52, 25, 204, 0.05);
margin: 0 12px;
margin-bottom: 8px;
display: flex;
justify-content: center;
align-items: center;
background-color: #00a6ff;
height: 44px;
border-radius: 50px;
}
.audio-visualizer {
display: flex;
align-items: center;
justify-content: center;
height: 20px;
gap: 2px;
}
.audio-bar {
width: 2px;
height: 4px;
border-radius: 2px;
background-color: #fff;
}
</style>