• 设为首页
  • 收藏本站
  • 积分充值
  • VIP赞助
  • 手机版
  • 微博
  • 微信
    微信公众号 添加方式:
    1:搜索微信号(888888
    2:扫描左侧二维码
  • 快捷导航
    福建二哥 门户 查看主题

    Vue使用wavesurfer.js实现音频可视化的示例详解

    发布者: 土豆服务器 | 发布时间: 2025-6-16 07:41| 查看数: 54| 评论数: 0|帖子模式

    WaveSurfer.js是一个开源的音频可视化库,用于创建交互式、可定制的波形。文章详细介绍了配置选项,包括播放速度、音频渲染、波形样式、交互性等,并提供了事件处理方法如播放、暂停、音量控制等。本文要实现的效果图如下:


    安装

    按照官方文档步骤

    1.安装
    1. npm install --save wavesurfer.js
    复制代码
    2.引入
    1. import WaveSurfer from 'wavesurfer.js'
    2. //需要时间轴的话需要引入
    3. import Timeline from 'wavesurfer.js/dist/plugins/timeline.esm.js'
    复制代码
    封装Vue 组件

    接下来,我们将 WaveSurfer.js 封装成一个 Vue 组件,方便在项目中复用。以下是完整的组件代码
    1. <template>
    2.     <div id="aiccAudio">
    3.         <el-card>
    4.             <div id="wavefrom" ref="wavefrom" @click="getTime">
    5.             </div>
    6.         </el-card>
    7.         <div class="audio-controlBar">
    8.             <!-- 播放/暂停按钮 -->
    9.             <button @click="playMusic">
    10.                 <i v-if="videoPlay" class="el-icon-video-play"></i>
    11.                 <i v-else class="el-icon-video-pause"></i>
    12.             </button>
    13.             <!-- 时间  -->
    14.             <div class="audio-time">
    15.                 <div class="audio-current-time" aria-label="time">{{ currentTime }}</div>
    16.                 <span class="audio-fen-line">|</span>
    17.                 <div class="audio-duration" aria-label="duration">{{ duration }}</div>
    18.             </div>
    19.             <!-- 倍速  -->
    20.             <span style="margin-left: 80px;margin-right: 10px;">倍速</span>
    21.             <el-select class="audio-speed" v-model="speedValue" @change="speedChange">
    22.                 <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
    23.                 </el-option>
    24.             </el-select>
    25.             <!-- <span class="audio-line">|</span> -->
    26.             <!--  音量  -->
    27.             <div class="audio-volume">
    28.                 <img v-if="audioVolumeStatus == true" @click="volumeStatusChange('open')" class="audio-volume-img"
    29.                     src="../../../../public/images/voice_open.png">
    30.                 <img v-else class="audio-volume-img" @click="volumeStatusChange('close')"
    31.                     src="../../../../public/images/voice_close.png">
    32.                 <el-slider class="audio-volume-slider" v-model="volume" @input="volumeChange"></el-slider>
    33.             </div>
    34.         </div>
    35.     </div>
    36. </template>
    37. <script>
    38. import WaveSurfer from 'wavesurfer.js' //导入wavesurfer.js
    39. import Timeline from 'wavesurfer.js/dist/plugins/timeline.esm.js' //导入时间轴插件
    40. export default {
    41.     name: 'AiccAudio',
    42.     props: {
    43.         src: {
    44.             type: String
    45.         },
    46.         recordPath: {
    47.             type: String
    48.         }
    49.     },
    50.     data() {
    51.         return {
    52.             wavesurfer: null,
    53.             timer: null,
    54.             options: [
    55.                 {
    56.                     value: '0.5',
    57.                     label: '0.5',
    58.                 }, {
    59.                     value: '1.0',
    60.                     label: '1.0',
    61.                 }, {
    62.                     value: '1.5',
    63.                     label: '1.5',
    64.                 }, {
    65.                     value: '2.0',
    66.                     label: '2.0',
    67.                 }
    68.             ],
    69.             speedValue: '1.0',
    70.             currentTime: '00:00:00', //当前播放
    71.             duration: '00:00:00', //总时长
    72.             volume: 30,//音量,
    73.             audioVolumeStatus: false, //是否静音
    74.             videoPlay: true,
    75.         }
    76.     },
    77.     created() {
    78.         this.keyDown();
    79.     },
    80.     mounted() {
    81.         this.$nextTick(() => {
    82.             if (this.recordPath != null && this.recordPath != '') {
    83.                 this.wavesurfer = WaveSurfer.create({
    84.                     container: this.$refs.wavefrom,
    85.                     height: 128,
    86.                     waveColor: 'rgb(200, 0, 200)',
    87.                     progressColor: '#00f2fe',
    88.                     cursorColor: '#00f2fe', //指示播放头位置的光标填充颜色
    89.                     cursorWidth: 2,
    90.                     // backend: 'MediaElement',
    91.                     mediaControls: false,
    92.                     audioRate: this.speedValue,
    93.                     hideScrollbar: true,
    94.                     setPlaybackRate: [0.5, 1.0, 1.5, 2.0],
    95.                     //使用时间轴插件
    96.                     plugins: [Timeline.create()],
    97.                 })
    98.                 this.wavesurfer.load('http://localhost:9527/89A3099B9253566.mp3')
    99.                 console.log(this.wavesurfer)
    100.                 //音频加载完成触发
    101.                 this.wavesurfer.on("ready", () => {
    102.                     this.wavesurfer.setVolume(this.volume / 100);
    103.                     this.duration = this.formatSecond(this.wavesurfer.getDuration())
    104.                 });
    105.                 this.wavesurfer.on('click', () => {
    106.                     this.wavesurfer.play()
    107.                     this.videoPlay = false
    108.                 })
    109.             }
    110.         })
    111.     },
    112.     methods: {
    113.         getSoundUrl(options) {
    114.             // 具体请求怎么写就看每个人的项目用的是什么了
    115.             return axios.get(url, { responseType: 'blob' })
    116.                 .then(res => {
    117.                     if (!res.headers['content-disposition']) {
    118.                         return console.error('文件名称不存在');
    119.                     }
    120.                     // 获取到的blob类型文件地址
    121.                     return URL.createObjectURL(res.data);
    122.                 })
    123.                 .catch(err => {
    124.                     console.error('文件获取失败');
    125.                 })
    126.         },
    127.         playMusic() {
    128.             if (this.recordPath != null && this.recordPath != '') {
    129.                 //"播放/暂停"按钮的单击触发事件,暂停的话单击则播放,正在播放的话单击则暂停播放
    130.                 this.wavesurfer.playPause.bind(this.wavesurfer)();
    131.                 //每秒获取进度 有时间轴时使用
    132.                 // this.getProcess();
    133.                 //判断是否播放
    134.                 this.videoPlay = this.wavesurfer.isPlaying() == true ? false : true;
    135.                 //音频播放时触发
    136.                 this.wavesurfer.on("audioprocess", () => {
    137.                     this.currentTime = this.formatSecond(this.wavesurfer.getCurrentTime())
    138.                 })
    139.                 //结束播放
    140.                 this.wavesurfer.on("finish", () => {
    141.                     this.wavesurfer.stop();
    142.                     this.videoPlay = true;
    143.                     this.currentTime = '00:00:00'
    144.                 });
    145.             }
    146.         },
    147.         formatSecond(seconds) {
    148.             // console.log(seconds)
    149.             // 确保输入是数字类型
    150.             if (typeof seconds !== 'number' || isNaN(seconds)) {
    151.                 this.$message.error('error')
    152.             }
    153.             // 将秒数拆分为小时、分钟和秒
    154.             const totalSeconds = Math.floor(seconds); // 只保留整数部分
    155.             const hours = String(Math.floor(totalSeconds / 3600)).padStart(2, '0'); // 计算小时并补零
    156.             const minutes = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0'); // 计算分钟并补零
    157.             const secs = String(totalSeconds % 60).padStart(2, '0'); // 计算秒并补零

    158.             return `${hours}:${minutes}:${secs}`;
    159.         },
    160.         //有时间轴时使用
    161.         // getProcess(){
    162.         //   if(this.wavesurfer.isPlaying()){
    163.         //     this.timer=setInterval(()=>{
    164.         //       this.percent=(this.wavesurfer.getCurrentTime().toFixed(0)/this.wavesurfer.getDuration()*100).toFixed(0)
    165.         //       this.config={
    166.         //         value:this.percent
    167.         //       }
    168.         //     },1000)
    169.         //   }else{
    170.         //     clearInterval(this.timer)
    171.         //   }
    172.         // },
    173.         //点击获取点击进度
    174.         getTime() {
    175.             if (this.recordPath != null && this.recordPath != '') {
    176.                 //加定时器,不然获取的是点击前的播放时间
    177.                 setTimeout(() => {
    178.                     this.currentTime = this.formatSecond(this.wavesurfer.getCurrentTime())
    179.                     ///有时间轴时使用
    180.                     // this.percent=(this.wavesurfer.getCurrentTime()/this.wavesurfer.getDuration()*100).toFixed(0)
    181.                     // this.config={
    182.                     //   value:this.percent
    183.                     // }
    184.                 }, 100)
    185.             }
    186.         },
    187.         //按键跳转进度
    188.         // jump(e){
    189.         // this.wavesurfer.play([e.target.innerHTML-0])
    190.         // this.percent=(this.wavesurfer.getCurrentTime().toFixed(0)/this.wavesurfer.getDuration()*100).toFixed(0)
    191.         // this.config={
    192.         //   value:this.percent
    193.         // }
    194.         // this.getProcess()
    195.         // },
    196.         // 监听键盘
    197.         keyDown() {
    198.             if (this.recordPath != null && this.recordPath != '') {
    199.                 document.onkeydown = (e) => {
    200.                     //事件对象兼容
    201.                     var eCode = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode;
    202.                     //键盘按键判断:左箭头-37;上箭头-38;右箭头-39;下箭头-40
    203.                     //左
    204.                     if (eCode == 37) {
    205.                         // 按下左箭头
    206.                         this.wavesurfer.skip(-6)
    207.                         this.getTime()
    208.                     } else if (eCode == 39) {
    209.                         // 按下右箭头
    210.                         this.wavesurfer.skip(6)
    211.                         this.getTime()
    212.                     }
    213.                 }
    214.             }
    215.         },
    216.         //倍速
    217.         speedChange(val) {
    218.             if (this.recordPath != null && this.recordPath != '') {
    219.                 this.speedValue = val;
    220.                 this.wavesurfer.setPlaybackRate(this.speedValue)
    221.             }
    222.         },
    223.         //音量大小改变
    224.         volumeChange(val) {
    225.             if (this.recordPath != null && this.recordPath != '') {
    226.                 this.volume = val;
    227.                 if (this.wavesurfer != null) {
    228.                     this.wavesurfer.setVolume(val / 100);
    229.                 }
    230.                 if (val == '0') {
    231.                     this.audioVolumeStatus = false
    232.                 } else {
    233.                     this.audioVolumeStatus = true
    234.                 }
    235.             }
    236.         },
    237.         //静音开启关闭
    238.         volumeStatusChange(status) {
    239.             if (this.recordPath != null && this.recordPath != '') {
    240.                 if (status == 'open') {
    241.                     this.audioVolumeStatus = false
    242.                     this.volume = 0;
    243.                     this.wavesurfer.setVolume(0);
    244.                 } else {
    245.                     this.audioVolumeStatus = true
    246.                     this.volume = 30;
    247.                     this.wavesurfer.setVolume(30 / 100);
    248.                 }
    249.             }
    250.         }
    251.     }
    252. }

    253. </script>
    254. <style lang="scss" scoped>
    255. .audio-controlBar {
    256.     background-color: #f4f6f9;
    257.     padding: 0 10px;
    258.     border-radius: 10px;

    259.     button {
    260.         border: none;
    261.         background-color: #f4f6f9;
    262.     }

    263.     i {
    264.         //color: #95979f;
    265.         color: #1053ee;
    266.     }
    267. }

    268. //时间
    269. .audio-time {
    270.     display: inline-block;
    271.     font-size: 12px;
    272.     color: #95979f;
    273.     margin: 0 10px;
    274. }

    275. .audio-current-time {
    276.     display: inline-block;
    277.     color: #1053ee;
    278. }

    279. .audio-fen-line {
    280.     margin: 0 5px;
    281. }

    282. .audio-duration {
    283.     display: inline-block;
    284. }

    285. //倍速
    286. .audio-speed {
    287.     width: 68px;
    288.     // margin-left: 85px;

    289.     .el-input__inner {
    290.         background-color: #f4f6f9;
    291.     }
    292. }

    293. .audio-line {
    294.     color: #95979f;
    295.     margin-right: 5px;
    296. }

    297. //音量条
    298. .audio-volume {
    299.     width: 166px;
    300.     float: right;

    301.     .audio-volume-slider {
    302.         width: 110px;
    303.         float: right;
    304.     }
    305. }

    306. .audio-volume-img {
    307.     width: 18px;
    308.     margin-top: 12px;
    309. }
    310. </style>
    复制代码
    我为了方便测试,音频路径是写在里面的,有用的同学可以根据项目需求传入组件中,样式功能啥的可以自行调整。

    总结

    通过 WaveSurfer.js,我们可以轻松实现音频的可视化与播放控制。本文介绍的 Vue 组件封装了常见的音频播放功能,包括播放/暂停、倍速控制、音量调节等,方便在项目中复用。根据项目需求,可以进一步调整样式和功能。
    以上就是Vue使用wavesurfer.js实现音频可视化的示例详解的详细内容,更多关于Vue wavesurfer.js音频可视化的资料请关注脚本之家其它相关文章!

    来源:https://www.jb51.net/javascript/339416vkx.htm
    免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    ×

    最新评论

    QQ Archiver 手机版 小黑屋 福建二哥 ( 闽ICP备2022004717号|闽公网安备35052402000345号 )

    Powered by Discuz! X3.5 © 2001-2023

    快速回复 返回顶部 返回列表