小程序无法用 uni.getRecorderManager().onFrameRecorded 获取实时PCM数据,因平台限制;应改用 recorder-core 的 powerLevel 定时估算振幅,配合 CSS 波形条动画实现跨端稳定波形图。

小程序内用 uni.getRecorderManager() 拿不到实时 PCM 帧数据,直接画波形图会卡顿、不准、甚至空白——根本原因是微信/支付宝等小程序平台不开放原始音频流,onFrameRecorded 在多数版本中不可用或被限制。
uni-app 小程序端无法用 onFrameRecorded 获取实时 PCM
很多教程照搬 H5 的 MediaRecorder 思路,或误以为小程序 recorderManager.onFrameRecorded 是稳定可用的。实际上:
- 微信基础库 2.25.0+ 才开始实验性支持
onFrameRecorded,且仅限部分机型,iOS 上几乎无效 - 支付宝、百度、字节小程序至今未开放该事件
- 即使触发,返回的
frameBuffer是压缩后的 ArrayBuffer(非标准 PCM),长度和采样率不固定,不能直接算 RMS - 频繁触发该回调会导致 JS 主线程阻塞,UI 动画掉帧
改用 recorder-core 的 powerLevel 做轻量振幅估算
真正跨小程序平台可行的方案是引入 recorder-core(不是官方插件,是 xiangyuecn 维护的兼容层),它绕过原生限制,用定时轮询 + 音频上下文分析模拟“功率等级”:
-
powerLevel是归一化后的 0–100 整数,代表当前帧相对能量强度,无需解析 PCM,开销极低 - 在
onProcess回调里每 100ms 左右取一次值,比原生onFrameRecorded更稳 - 需配合
start({encode:false})禁用编码,否则 powerLevel 始终为 0 - Vue 3 中注意 this 代理问题:用
const { proxy } = getCurrentInstance()访问proxy.$refs.wave
示例关键片段:
import Recorder from 'recorder-core';
// ...
const recorder = new Recorder({
sampleRate: 16000,
numberOfChannels: 1,
encode: false // 必须关掉
});
recorder.start();
recorder.onProcess = (pcmData, powerLevel) => {
waveAmplitudes.value.unshift(powerLevel / 100); // 归一化到 0–1
if (waveAmplitudes.value.length > 60) waveAmplitudes.value.pop();
};
用 CSS 动画替代 Canvas 实现低成本波形条
小程序 Canvas 渲染性能差,尤其在低端安卓机上,每帧重绘 60 条波形极易掉帧。更务实的做法是用纯 CSS:
- 用
<view class="wave-bar"></view>循环渲染 40–60 个竖条,高度由v-bind:style="{ height: amp * 40 + 'rpx' }"控制 - 加
transition: height 0.15s ease-out实现自然衰减动画 - 避免用
transform: scaleY(),某些小程序 WebView 对 transform 动画支持不一致 - 高度单位统一用
rpx,避免 H5 和小程序尺寸错位
audio-wave 组件的 maxHeight 和 waveCount 必须配对调整
第三方组件如 audio-wave 看似开箱即用,但参数不匹配会导致波形挤成一条线或超出容器:
-
maxHeight是单条最大像素高度(如 35),但实际显示高度还受waveCount和父容器宽度影响 -
waveCount必须为偶数(文档明确要求),否则内部计算越界,部分条目高度为 0 - 若设
waveCount: 60但父容器宽度只有 300rpx,每条宽度不足 5rpx,视觉上就糊成一片 - 建议先固定
waveCount: 48,再按maxHeight: Math.min(35, containerWidth / 12)动态算最大高度
真正难的不是画出波形,而是让不同机型、不同基础库版本下,振幅变化能被用户明显感知——这依赖 powerLevel 的稳定性、CSS 过渡时长的微调、以及对静音阈值(比如连续 3 帧 powerLevel 就清零)的合理判断。


















