wq-audio-player
v1.1.1
Published
功能强大的HTML5音频播放器,支持Vue/React、频谱可视化、进度拖拽、试听模式、资源保护等高级功能
Maintainers
Readme
WQ Audio Player
一个功能强大、美观的HTML5音频播放器,支持Vue、React等框架,内置频谱可视化、试听模式、国际化、缓存进度显示等高级功能。
✨ 功能特性
- 🎨 美观的毛玻璃效果UI设计,支持自定义主题色
- 🎵 实时音频频谱可视化效果(环形声浪+底部频谱)
- 🎚️ 进度条拖拽功能,支持长按圆圈自由调整播放进度
- ⏯️ 完整播放控制(播放/暂停、快退/快进15秒、音量调节)
- ⚡ 倍速播放(0.5x - 2x)
- 🔁 重新播放功能
- 🖥️ 全屏播放支持
- ⏱️ 试听模式,可限制播放时长
- 💰 试听结束自定义购买按钮
- 🌍 内置国际化支持(简体中文/英文)
- 📦 缓存进度实时显示
- 📱 响应式设计,适配移动端触摸操作
- ⌨️ 键盘快捷键支持(空格键播放/暂停)
- 🔧 高度可配置,支持跨域设置
- 🔌 支持原生JS、Vue、React等所有前端框架
- 🔒 内置资源保护:自动将音频转为Blob URL,隐藏原始音频地址
- 🕵️ Audio元素深度隐藏,大幅提升音频资源被盗取的难度
📦 安装
npm安装
npm install wq-audio-player --saveCDN引入
<link rel="stylesheet" href="https://unpkg.com/wq-audio-player/dist/style.css">
<script src="https://unpkg.com/wq-audio-player/dist/index.js"></script>🚀 基础使用
原生JavaScript
<div id="audio-player"></div>
<script>
const player = new WqAudioPlayer('#audio-player', {
audioUrl: 'https://example.com/audio.mp3',
coverUrl: 'https://example.com/cover.jpg',
title: '歌曲名称',
artist: '歌手名称',
previewSeconds: 10, // 试听10秒
showPurchaseButton: true, // 显示购买按钮
language: 'zh-CN' // 中文界面
});
// 监听事件
player.on('play', () => console.log('开始播放'));
player.on('purchase', () => window.location.href = '/buy');
</script>ES6模块导入
import WqAudioPlayer from 'wq-audio-player';
import 'wq-audio-player/dist/style.css';
const player = new WqAudioPlayer('#player-container', {
audioUrl: '你的音频地址.mp3',
title: '歌曲名称',
width: '500px',
musicColor: '#409eff'
});⚙️ 完整配置项
| 参数名 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| audioUrl | string | '' | 音频地址(必填) |
| coverUrl | string | 'https://picsum.photos/seed/music/400/400' | 专辑封面地址 |
| title | string | 'Unknown Title' | 歌曲标题 |
| showTitle | boolean | true | 是否显示歌曲标题 |
| artist | string | 'Unknown Artist' | 歌手名称 |
| showArtist | boolean | false | 是否显示歌手名称 |
| autoplay | boolean | false | 是否自动播放(受浏览器策略限制) |
| width | string | '100%' | 播放器宽度 |
| height | string | 'auto' | 播放器高度 |
| previewSeconds | number | 0 | 试听时长(秒),0表示不限制 |
| showPurchaseButton | boolean | false | 试听结束后是否显示购买按钮 |
| purchaseButtonText | string | undefined | 购买按钮自定义文字,默认使用当前语言翻译 |
| purchaseButtonBgColor | string | '#409eff' | 购买按钮背景色 |
| purchaseButtonTextColor | string | '#ffffff' | 购买按钮文字颜色 |
| cvHeight | string | '200px' | 频谱画布高度 |
| musicColor | string | '#fff' | 频谱波形颜色 |
| speedOptions | array | [0.5, 0.75, 1, 1.25, 1.5, 2] | 倍速可选值列表 |
| crossOrigin | string/boolean | 'anonymous' | 音频跨域配置,可选值:'anonymous'、'use-credentials'、false |
| language | string | 'zh-CN' | 界面语言,支持:'zh-CN'(简体中文)、'en-US'(英文) |
| showCircularWave | boolean | true | 是否显示碟片环形声浪效果 |
| showBottomWave | boolean | false | 是否显示底部频谱音浪效果 |
| t | function | 内置翻译函数 | 自定义翻译函数,用于扩展多语言 |
| onPlay | function | undefined | 播放事件回调 |
| onPause | function | undefined | 暂停事件回调 |
| onEnded | function | undefined | 播放结束回调 |
| onPreviewEnded | function | undefined | 试听结束回调 |
| onSeek | function | undefined | 进度跳转回调 |
| onPurchase | function | undefined | 购买按钮点击回调 |
| onError | function | undefined | 音频加载错误回调 |
🎧 事件回调
| 事件名 | 说明 | 回调参数 |
|--------|------|----------|
| play | 开始播放时触发 | - |
| pause | 暂停播放时触发 | - |
| ended | 播放结束时触发 | - |
| previewEnded | 试听结束时触发 | - |
| seek | 拖动进度条跳转播放时触发 | currentTime(跳转后的时间点,秒) |
| purchase | 点击购买按钮时触发 | - |
| error | 音频加载错误时触发 | errorInfo(错误信息对象,包含错误类型和提示) |
事件监听示例
// 监听播放事件
player.on('play', () => {
console.log('音频开始播放');
});
// 监听错误事件
player.on('error', (error) => {
console.error('音频加载失败:', error);
if (error.type === 'cors') {
alert('音频跨域访问被限制,请检查服务器配置');
}
});
// 监听购买按钮点击
player.on('purchase', () => {
// 跳转到购买页面
window.location.href = '/buy-audio';
});🛠️ 实例方法
| 方法名 | 说明 | 参数 |
|--------|------|------|
| togglePlay() | 切换播放/暂停状态 | - |
| handleBackward() | 后退15秒 | - |
| handleForward() | 前进15秒 | - |
| setPlaybackRate(rate) | 设置播放倍速 | rate: 倍速值 |
| toggleMute() | 切换静音状态 | - |
| toggleLoop() | 重新播放(回到开始位置并播放) | - |
| handleFullscreen() | 切换全屏模式 | - |
| setAudioUrl(url) | 切换音频地址 | url: 新的音频地址 |
| on(eventName, callback) | 监听事件 | eventName: 事件名, callback: 回调函数 |
| destroy() | 销毁播放器实例,释放资源 | - |
🔌 框架集成
Vue 3 使用示例
<template>
<div ref="playerRef"></div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import WqAudioPlayer from 'wq-audio-player';
import 'wq-audio-player/dist/style.css';
const playerRef = ref(null);
let player = null;
onMounted(() => {
player = new WqAudioPlayer(playerRef.value, {
audioUrl: 'https://example.com/audio.mp3',
title: 'Vue3项目示例',
previewSeconds: 10,
showPurchaseButton: true
});
player.on('play', () => {
console.log('播放开始');
});
});
onUnmounted(() => {
player?.destroy();
});
</script>Vue 2 使用示例
<template>
<div ref="playerRef"></div>
</template>
<script>
import WqAudioPlayer from 'wq-audio-player';
import 'wq-audio-player/dist/style.css';
export default {
data() {
return {
player: null
}
},
mounted() {
this.player = new WqAudioPlayer(this.$refs.playerRef, {
audioUrl: 'https://example.com/audio.mp3',
title: 'Vue2示例'
});
},
beforeDestroy() {
this.player?.destroy();
}
}
</script>React 使用示例
import { useEffect, useRef } from 'react';
import WqAudioPlayer from 'wq-audio-player';
import 'wq-audio-player/dist/style.css';
const AudioPlayer = () => {
const playerRef = useRef(null);
const playerInstance = useRef(null);
useEffect(() => {
if (!playerInstance.current && playerRef.current) {
playerInstance.current = new WqAudioPlayer(playerRef.current, {
audioUrl: 'https://example.com/audio.mp3',
title: 'React项目示例',
language: 'en-US' // 英文界面
});
playerInstance.current.on('purchase', () => {
console.log('跳转到购买页面');
});
}
return () => {
playerInstance.current?.destroy();
playerInstance.current = null;
};
}, []);
return <div ref={playerRef}></div>;
};
export default AudioPlayer;🌍 国际化
切换语言
const player = new WqAudioPlayer('#player', {
// ...其他配置
language: 'en-US' // 切换为英文界面
});自定义多语言
const player = new WqAudioPlayer('#player', {
// ...其他配置
language: 'ja-JP',
t: function(key, params) {
// 自定义日语翻译
const translations = {
'audio.albumCover': 'アルバムカバー',
'audio.previewEnded': '試聴終了',
'audio.previewDescription': '試聴が終了しました。完全版を購入してください。試聴時間: {seconds}秒',
'audio.purchaseButton': '購入する'
};
let text = translations[key] || key;
if (params) {
Object.keys(params).forEach(k => {
text = text.replace(`{${k}}`, params[k]);
});
}
return text;
}
});⌨️ 键盘快捷键
- 空格键:播放/暂停(播放器聚焦时有效)
❓ 常见问题
1. 音频加载跨域错误
Access to audio at 'xxx' from origin 'xxx' has been blocked by CORS policy解决方法:
- 配置音频资源服务器的CORS规则,允许你的域名访问
- 如果是阿里云OSS,需要在控制台配置跨域规则:
- 允许Methods:
GET、HEAD、OPTIONS - 允许Headers:
* - 暴露Headers:
ETag、Content-Length、Content-Range、Accept-Ranges
- 允许Methods:
- 如果不需要频谱功能,可以设置
crossOrigin: false,可以绕过跨域限制正常播放
2. 自动播放不生效
浏览器安全策略限制音频自动播放,需要用户交互(如点击页面)后才能自动播放,可以在用户点击事件回调中调用player.togglePlay()触发播放。
3. 频谱不显示
需要确保:
- 音频地址配置了正确的CORS规则
crossOrigin参数设置为'anonymous'- 音频格式是浏览器支持的格式(mp3/wav/ogg等)
4. 关于音频资源保护
播放器内置的Blob转码和元素隐藏功能,可以:
- ✅ 隐藏原始音频URL,用户在DOM中只能看到
blob:开头的临时地址 - ✅ 防止普通用户直接获取和分享原始音频链接
- ✅ Blob URL仅在当前页面上下文有效,关闭页面或刷新后立即失效
- ❌ 无法100%防止专业技术人员通过抓包等方式获取音频(完全防下载需要服务端配合实现加密流媒体)
如果需要更高等级的版权保护,建议配合服务端实现:
- 音频URL签名和过期机制
- Referer防盗链校验
- HLS流媒体AES加密
浏览器兼容性
支持现代浏览器,需要支持以下API:
- AudioContext
- requestAnimationFrame
- requestFullscreen
- ES6+语法
更新日志
v1.1.1
- 🔧 新增 ES5 兼容性构建,通过 Babel 转译支持不支持 ES6 的老项目
- 📦 默认输出指向 ES5 版本,保持源码版本同时提供向后兼容
- ✅ 完全兼容 Vue 2 / Vue 3 / React 等所有前端框架
- 提供多种格式输出:UMD, CommonJS, ES Module
v1.1.0
- ✨ 新增进度条拖拽功能,支持长按圆圈自由调整播放进度
- ✨ 拖拽过程中实时显示时间,进度条不被自动更新影响
- ✨ 支持鼠标和移动端触摸操作
- ✨ 拖拽时鼠标样式动态变化(手掌/抓手)
- ✨ 新增频谱显示开关配置:
showCircularWave和showBottomWave - 🐛 优化拖拽交互体验,兼容试听时长限制
- ✨ 新增音频资源保护功能,自动将音频转为Blob URL隐藏原始地址
- 🐛 优化Blob资源释放逻辑,避免内存泄漏
- 🐛 新增加载失败降级机制,当Blob加载失败时自动使用原始URL
📄 许可证
MIT License
