Skip to content

简单微信小程序开发案例——瞬间听力测试

项目名称

微信搜索:瞬间听力测试

项目预览

项目概述

这是一个基于 Vue 3 + uni-app 开发的瞬间听力测试游戏,玩家需要在听到一串数字后准确输入。游戏从 7 位数字开始,最高可挑战 20 位数字,支持三种难度模式(舒缓、正常、急促),具有精美的 UI 设计和流畅的交互体验。

核心功能特性

  • 渐进式难度:从 7 位数字开始,成功后自动升级到下一关
  • 多难度模式:三种语音播放速度,适应不同用户需求
  • 实时音效反馈:按钮点击音效和声波可视化
  • 智能语音播报:基于微软 TTS 的高质量语音合成
  • 响应式设计:适配多种屏幕尺寸
  • 社交分享:支持微信分享,动态生成个性化标题

技术架构

前端技术栈

  • 框架:Vue 3 Composition API + uni-app
  • 样式:SCSS + 主题系统
  • 状态管理:Composables 模式
  • 音频处理:微信小程序音频 API

后端服务

  • TTS 服务:微软开源 TTS 镜像部署
  • API 接口:RESTful API 设计
  • 音频格式:MP3 流式传输

CSS 巧妙用法详解

1. 主题系统设计

项目采用了基于 SCSS Map 的主题系统,支持三种视觉风格:

scss
$themes: (
  easy: (
    start: #d6d3ac,
    secondary: #d5d693,
    accent: #a5d6a7,
    primary: #81c784,
    end: #81c784,
    shadow: rgba(129, 199, 132, 0.35),
  ),
  normal: (
    start: #f8bbd9,
    secondary: #e1bee7,
    accent: #81d4fa,
    primary: #4fc3f7,
    end: #29b6f6,
    shadow: rgba(41, 182, 246, 0.4),
  ),
  hard: (
    start: #fcbc81,
    secondary: #ffac75,
    accent: #ffabad,
    primary: #ff9393,
    end: #ff7072,
    shadow: rgba(255, 112, 114, 0.45),
  ),
);

@mixin theme-gradient($theme-name) {
  $theme: map-get($themes, $theme-name);
  background: linear-gradient(
    135deg,
    map-get($theme, start),
    map-get($theme, secondary),
    map-get($theme, accent),
    map-get($theme, primary),
    map-get($theme, end)
  );
}

@each $theme-name, $theme in $themes {
  &.theme-#{$theme-name} {
    @include theme-gradient($theme-name);
  }
}

技术亮点

  • 使用 @each 循环自动生成主题变体
  • 通过 map-get() 函数动态获取主题色彩
  • 支持运行时主题切换,无需重新编译

2. 声波动画效果

scss
@keyframes playingWave {
  0%,
  100% {
    height: 15rpx;
    transform: scaleY(1);
  }
  50% {
    height: 80rpx;
    transform: scaleY(1.2);
  }
}

$wave-colors: (
  1: linear-gradient(to top, #4fc3f7, #81d4fa),
  2: linear-gradient(to top, #ce93d8, #e1bee7),
  3: linear-gradient(to top, #ffcc80, #ffb74d),
  4: linear-gradient(to top, #a5d6a7, #81c784),
  5: linear-gradient(to top, #f8bbd9, #f48fb1),
);

@each $index, $gradient in $wave-colors {
  &:nth-child(#{$index}) {
    background: $gradient;
    &.playing {
      animation-delay: #{$index * -0.2}s;
    }
  }
}

动画亮点

  • 每个波形条独立的渐变色彩
  • 错位的动画延迟创建波浪效果
  • 加载和播放两种不同的动画状态

音效生成技术

1. 程序化音效合成

项目采用 Web Audio API 原理,通过数学算法生成按钮点击音效:

javascript
const initClickSound = () => {
  const sampleRate = 44100;
  const duration = 0.02;
  const samples = Math.floor(sampleRate * duration);
  const buffer = new ArrayBuffer(44 + samples * 2);
  const view = new DataView(buffer);

  // WAV 文件头生成
  const writeString = (offset, string) => {
    for (let i = 0; i < string.length; i++) {
      view.setUint8(offset + i, string.charCodeAt(i));
    }
  };

  // 音频数据生成
  for (let i = 0; i < samples; i++) {
    const t = i / sampleRate;
    const progress = t / duration;
    const frequency = 1200; // 清脆的点击声频率
    const envelope = Math.exp(-progress * 15); // 快速衰减包络
    const sample = Math.sin(2 * Math.PI * frequency * t) * envelope * 0.3;
    const intSample = Math.max(
      -32768,
      Math.min(32767, Math.floor(sample * 32767))
    );
    view.setInt16(44 + i * 2, intSample, true);
  }
};

技术优势

  • 零延迟:无需网络请求,本地生成
  • 体积小:20ms 音效仅几 KB
  • 可定制:频率、包络、音量可调
  • 兼容性好:标准 WAV 格式,全平台支持

2. 音频池优化策略

javascript
const initAudioPool = (audioPath) => {
  audioPool = [];
  for (let i = 0; i < poolSize; i++) {
    const audio = wx.createInnerAudioContext();
    audio.src = audioPath;
    audio.volume = 0.45;
    audio.autoplay = false;
    audioPool.push(audio);
  }
};

const playClickSound = () => {
  if (audioPool.length > 0) {
    const audio = audioPool[currentPoolIndex];
    audio.play();
    currentPoolIndex = (currentPoolIndex + 1) % poolSize;
  }
};

优化原理

  • 预加载:避免播放时的延迟
  • 轮询使用:防止音频实例冲突
  • 内存管理:固定池大小,控制资源占用

语音播报后端实现

1. 微软 TTS 服务部署

项目使用微软开源的 TTS 镜像

Docker 部署命令

bash
docker run -d \
  --name microsoft-tts \
  -p 8080:8080 \
  -e AZURE_SPEECH_KEY=your_key \
  -e AZURE_SPEECH_REGION=your_region \
  microsoft/cognitive-services-speech-to-text

API 接口设计

javascript
const playTTS = (text, voice, speed) => {
  return uni.request({
    url: "https://xxx.com/tts/v1/audio/speech",
    method: "POST",
    data: {
      input: text,
      voice: "zh-CN-XiaoyiNeural", // 微软小艺语音
      response_format: "mp3",
      speed: speed || 1.0,
    },
    responseType: "arraybuffer",
  });
};

2. 音频流处理

javascript
const playAudio = () => {
  isLoading.value = true;
  uni.request({
    // ... API 配置
    success: (res) => {
      // 生成唯一文件名避免缓存冲突
      const timestamp = Date.now();
      const random = Math.floor(Math.random() * 1000);
      const filePath = `${uni.env.USER_DATA_PATH}/audio_${timestamp}_${random}.mp3`;

      fs.writeFile({
        filePath: filePath,
        data: res.data,
        encoding: "binary",
        success: () => {
          isLoading.value = false;
          isPlaying.value = true;
          innerAudioContext.src = filePath;
          innerAudioContext.play();

          // 播放完成后清理临时文件
          innerAudioContext.onEnded(() => {
            isPlaying.value = false;
            fs.unlink({ filePath });
          });
        },
      });
    },
  });
};

技术特点

  • 流式处理:ArrayBuffer 直接写入文件
  • 临时文件管理:播放后自动清理,节省存储
  • 状态同步:加载和播放状态实时更新 UI
  • 错误处理:网络异常时的优雅降级

3. 语音参数优化

javascript
const difficulties = {
  easy: { speed: 0.7, label: "舒缓" },
  normal: { speed: 1.0, label: "正常" },
  hard: { speed: 1.5, label: "急促" },
};

语音配置

  • 语音模型zh-CN-XiaoyiNeural(微软小艺,自然度高)
  • 音频格式:MP3(压缩率好,兼容性强)
  • 速度调节:0.7x - 1.5x 范围,适应不同难度

项目架构设计

1. 项目目录结构

memory-game/
├── .gitignore                    # Git 忽略文件配置
├── .hbuilderx/                   # HBuilderX 编辑器配置
│   └── launch.json              # 启动配置
├── .prettierrc.cjs              # 代码格式化配置
├── App.vue                      # 应用根组件
├── components/                   # 可复用组件目录
│   ├── CustomToast.vue          # 自定义提示组件
│   ├── DifficultySelector.vue   # 难度选择器组件
│   ├── NumberKeypad.vue         # 数字键盘组件
│   └── SoundWave.vue            # 声波可视化组件
├── composables/                  # 组合式函数目录
│   ├── useAudio.js              # 音频处理逻辑
│   └── useGame.js               # 游戏核心逻辑
├── pages/                        # 页面目录
│   └── index/                   # 首页目录
│       └── index.vue            # 游戏主页面
├── index.html                   # HTML 入口文件
├── main.js                      # 应用入口文件
├── manifest.json                # uni-app 应用配置
├── pages.json                   # 页面路由配置
├── uni.promisify.adaptor.js     # uni-app Promise 适配器
└── uni.scss                     # 全局样式文件

目录设计原则

  • 组件化components/ 存放可复用的 UI 组件
  • 逻辑分离composables/ 存放业务逻辑和状态管理
  • 页面隔离pages/ 按功能模块组织页面文件
  • 配置集中:根目录存放各种配置文件

2. Composables 模式

javascript
// useGame.js - 游戏逻辑
export function useGame() {
  const level = ref(7);
  const gameStatus = ref("initial");

  const startGame = () => {
    gameStatus.value = "playing";
    return generateNumber();
  };

  return { level, gameStatus, startGame };
}

// useAudio.js - 音频处理
export function useAudio() {
  const initAudio = () => {
    /* ... */
  };
  const playTTS = (text, voice, speed) => {
    /* ... */
  };

  return { initAudio, playTTS };
}

架构优势

  • 逻辑分离:游戏逻辑与音频处理解耦
  • 可复用性:Composables 可在多个组件中使用
  • 测试友好:纯函数易于单元测试

2. 组件化设计

  • CustomToast.vue:统一的消息提示组件
  • SoundWave.vue:声波可视化组件
  • DifficultySelector.vue:难度选择器
  • NumberKeypad.vue:数字键盘组件

性能优化策略

1. 音频优化

  • 音频池:避免频繁创建/销毁音频实例
  • 预加载:关键音效提前加载
  • 格式选择:MP3 平衡质量与体积

2. 内存管理

  • 临时文件清理:播放后立即删除
  • 组件懒加载:按需加载非关键组件
  • 事件监听清理:组件销毁时移除监听器

3. 用户体验

  • 零延迟输入:按钮响应与音效播放异步处理
  • 状态反馈:加载、播放状态的视觉提示
  • 错误处理:网络异常时的友好提示

总结

这个瞬间听力测试微信小程序项目展示了现代前端开发的多个技术亮点:

  1. CSS 工程化:主题系统、Mixin 复用、动画优化
  2. 音效技术:程序化合成、音频池优化
  3. 语音服务:微软 TTS 集成、流式音频处理
  4. 架构设计:Composables 模式、组件化开发
  5. 性能优化:内存管理、用户体验优化

项目不仅实现了完整的游戏功能,更在技术实现上体现了工程化思维和用户体验的深度考虑。通过合理的架构设计和优化策略,确保了应用在各种设备上的流畅运行。

Released under the MIT License.