uni-app中实现音乐播放器

uni-app中实现音乐播放器

1、主要利用的是uni-app中提供的uni.createInnerAudioContext()来进行实现;

2、代码示例

(1)主页面代码展示

<template><view class="music-layout"><view class="tn-flex"><view class="left-content"><view class="left-pic-layout"><img :src="bgUrl" :class="isPlay ? 'img-rotate' : ''"><view class="small-circle"></view></view><view class="like-layout"><text class="tn-icon-like-fill" v-if="musicDetail.liked" @click="onLikeMusic(false, musicDetail)"></text><text class="tn-icon-like" v-else @click="onLikeMusic(true, musicDetail)"></text></view></view><view class="right-content"><view class="song-name-layout"><view>{{ musicDetail.bsmb002 }}</view><view v-if="isPlay"><PlayerAnimation></PlayerAnimation></view></view><view class="progress-layout"><text>{{ formatTime(musicCurrentTime) }}</text><tn-slider:min="0":max="musicTotalTime"class="progress"v-model="musicCurrentTime"inactiveColor="#EAEAEA"activeColor="#FF3370":blockWidth="1":lineHeight="4"></tn-slider><text>{{formatTime(musicTotalTime)}}</text></view><view class="actions-layout"><view class="toggle-type-layout" @click="handleToggleType"><img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/loop-black-icon.png" v-if="toggleType == 1" ><img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/single-black-icon.png" v-else-if="toggleType == 2"><img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/random-black-icon.png" v-else></view><view class="action-center"><img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/previous-icon.png" class="previous-icon" @click="handlePreviousPlay"><img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/play-icon.png" v-if="isPlay" class="player-icon" @click="handlePlay(false)"><img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/stop-icon.png" v-else class="player-icon" @click="handlePlay(true)"><img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/next-icon.png" class="next-icon" @click="handleNextPlay"></view><img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/music-list.png" class="music-list-icon" @click="handleMusicListShow"></view></view></view><view class="add-music" @click="handleAddWisk">点这里添加您的音乐心愿单~</view></view>
</template><script>import { formatTime } from '@/utils/util'; // 代码在下方对应文件中
import PlayerAnimation from "../../../components/player-animation/player-animation.vue"; // 播放效果动画(代码在下方对应文件中)
import { musicList, saveCollect, cancleCollect } from "@/api/fetusMovement"; // 接口
import { mediaUrl } from '@/utils/env'; // 静态资源地址前缀export default {components: {PlayerAnimation},data() {return {isPlay: false, // 是否播放toggleType: 1, // 播放顺序 (1:循环;2:单曲循环;3:随机)musicDetail : { }, // 音乐详情current: null, // 当前播放的是哪首currentSrc: '', // 当前音乐路径musicPlayCtx: null, // 音频上下文musicCurrentTime: 0, // 音乐当前播放进度musicTotalTime: 100, // 音乐总的时间musicList: [], // 音乐列表bgUrl: 'http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/tjyy_bg.png',timers: null,openId: ''}},watch: {currentSrc: {handler() {if(this.musicPlayCtx) {this.musicPlayCtx.destroy();}this.musicPlayCtx = uni.createInnerAudioContext();this.musicPlayCtx.obeyMuteSwitch = false;this.musicCurrentTime = 0;this.musicPlayCtx.src = encodeURI(mediaUrl+ this.musicDetail.bsmb007);this.musicTotalTime = this.musicDetail.bsmb009;if(this.isPlay){this.handleAudioPlay();}},immediate: true,deep: true,}},mounted() {this.openId = getApp().globalData.openId;this.getMusicList();},methods: {// 打开音乐列表getMusicList() {musicList(this.openId).then(res => {if (res.success) {this.musicList = res.result;this.current = 0;this.musicDetail = this.musicList[this.current];this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);}})},// 播放列表弹窗显示handleMusicListShow() {const { isPlay, toggleType, musicList, current} = this;this.$emit('handleMusicListShow', {bool: true,isPlay,toggleType,musicList,current});},formatTime,// 处理播放handlePlay(bool) {this.isPlay = bool;if(bool) {this.musicPlayCtx.seek(this.musicCurrentTime + 1);this.handleAudioPlay();} else {this.musicPlayCtx.stop();}},// 播放handleAudioPlay() {this.musicPlayCtx.play();if(this.timers) {clearTimeout(this.timers);}this.timers = setTimeout(() => {console.log(this.musicPlayCtx.paused);}, 200);// 播放完成this.musicPlayCtx.onEnded(() => {if(this.toggleType == 1) {this.handleNextPlay(); // 列表循环} else if(this.toggleType == 2) {this.musicPlayCtx.play(); // 单曲循环} else {this.current = Math.floor(Math.random() * this.musicList.length);this.musicDetail = this.musicList[this.current];this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);}})// 更新播放时间this.musicPlayCtx.onTimeUpdate(() => {this.onTimeUpdate();})// 播放出现错误this.musicPlayCtx.onError(() => {this.onError();})},// 下一首handleNextPlay() {this.isPlay = true;if(this.current < this.musicList.length - 1) {uni.showToast({title: '即将播放下一首',icon: 'none'})this.current ++;this.musicDetail = this.musicList[this.current];this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);return}uni.showToast({title: '已经为最后一首了',icon: 'none'})},// 上一首handlePreviousPlay() {this.isPlay = true;if(this.current) {this.current --;uni.showToast({title: '即将播放上一首',icon: 'none'})this.musicDetail = this.musicList[this.current];this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);return;}uni.showToast({title: '已经为第一首了',icon: 'none'})},// 播放类型handleToggleType(parmas) {if(parmas) {this.toggleType = parmas;const { isPlay, toggleType, musicList, current} = this;this.$emit('handleMusicListShow', {bool: true,isPlay,toggleType,musicList,current});return;}this.toggleType = this.toggleType == 1 ? 2 : this.toggleType == 2 ? 3 : 1;},// 切换音乐handleMusicChange(index) {this.isPlay = true;this.musicDetail = this.musicList[index];this.current = index;this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);this.handleMusicListShow();},// 加载失败onError() {uni.showToast({title: '音频加载失败',icon: 'none'})},// 时间更新onTimeUpdate() {if (this.musicPlayCtx.currentTime > 0 && this.musicPlayCtx.currentTime <= 1) {this.musicCurrentTime = 1;} else if (this.musicCurrentTime !== Math.floor(this.musicPlayCtx.currentTime)) {this.musicCurrentTime = Math.floor(this.musicPlayCtx.currentTime);}},// 喜欢onLikeMusic(bool, item) {this.musicDetail.liked = bool;if (bool) {//收藏saveCollect({bsmId: item.id,openId: this.openId}).then(res => {if (res.success) {uni.showToast({title: '收藏成功',icon: 'none'})this.getMusicList()}})} else {//取消收藏cancleCollect({bsmId: item.id,openId: this.openId,id: item.collectId}).then(res => {if (res.success) {uni.showToast({title: '已取消收藏',icon: 'none'})this.getMusicList()}})}},// 心愿歌单handleAddWisk() {uni.navigateTo({url: '/toolsPages/fetusMovement/addWish'})}},// 销毁destroyed() {if(this.musicPlayCtx) this.musicPlayCtx.destroy();if(this.timers) clearTimeout(this.timers);}
}
</script><style scoped lang="scss">.music-layout {position: relative;width: 690rpx;padding: 20rpx 30rpx;background: #FFFFFF;border-radius: 30rpx;backdrop-filter: blur(16px);
}.left-content {width: 130rpx;.like-layout {margin-top: 20rpx;> text {color: #FF3370;font-size: 40rpx;}}
}.left-pic-layout {position: relative;width: 100rpx;height: 100rpx;border-radius: 50%;overflow: hidden;img {width: 100%;height: 100%;border-radius: 50%;}.small-circle{position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%);width: 20rpx;height: 20rpx;background-color: white;border-radius: 50%;}
}.right-content {flex: 1;margin-left: 30rpx;
}.song-name-layout {display: flex;justify-content: space-between;align-items: center;font-size: 32rpx;color: #323A59;line-height: 40rpx;height: 40rpx;text {color: rgba(115, 121, 141, 1);}
}.progress-layout {display: flex;justify-content: space-between;align-items: center;margin: 25rpx 0 0 2rpx;font-size: 26rpx;color: #73798D;line-height: 36rpx;.progress {display: flex;align-items: center;flex: 1;margin: 0 20rpx;}
}.actions-layout {display: flex;align-items: center;justify-content: space-between;margin: 25rpx 0 0 4rpx;.toggle-type-layout {> img {width: 30rpx;height: 26rpx;}}.action-center {display: flex;justify-content: space-between;align-items: center;flex: 1;margin: 0 86rpx;}.previous-icon, .next-icon {width: 30rpx;height: 32rpx;}.player-icon {width: 42rpx;height: 42rpx;}.music-list-icon {width: 30rpx;height: 30rpx;}
}.img-rotate {transform-origin: center center;animation: rotate 5s infinite linear; /* 实现旋转动画效果 */
}@keyframes rotate {from {transform: rotate(0deg);}to {transform: rotate(360deg);}
}.add-music {margin-top: 20rpx;text-align: center;font-size: 20rpx;color: #999999;text-decoration: underline #999999;
}
</style>

(2)utils中util.js文件代码

function fixedZero(val) {return val * 1 < 10 ? `0${val}` : val;
}const formatTime = (time) =>  {const minutes = 60;const m = Math.floor(time / minutes);const s = Math.floor(time % 60);return `${fixedZero(m)}:${fixedZero(s)}`;
}

(3)components中player-animation文件夹player-animation.vue文件代码

<template><view class="loading"><view class="item"></view><view class="item"></view><view class="item"></view><view class="item"></view><view class="item"></view></view>
</template><script>
export default {name: "player-animation"
}
</script><style scoped>
/* 设置位置 */
.loading {height: 24rpx;display: flex;align-items: center;
}.item {height: 24rpx;width: 2rpx;background: #FF3370;margin: 0 3rpx;border-radius: 10rpx;animation: loading 2s infinite;
}/* 设置动画 */
@keyframes loading {0% {height: 0;}50% {height: 24rpx;}100% {height: 0;}
}/* 为每一个竖条设置延时 */
.item:nth-child(2) {animation-delay: 0.2s;
}.item:nth-child(3) {animation-delay: 0.4s;
}.item:nth-child(4) {animation-delay: 0.6s;
}.item:nth-child(5) {animation-delay: 0.8s;
}</style>

(4)播放器列表弹窗代码

<template><tn-popup v-model="show"safeAreaInsetBottommode="bottom"height="1200rpx"@close="handleClose"><view class="music-container"><view class="header-layout"><view class="header-left">胎教音乐列表<text>({{ musicLst.length }}首)</text></view><view class="header-right" @click="() => handleToggle()"><img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/loop-icon.png" v-if="toggleType == 1" ><img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/single-icon.png" v-else-if="toggleType == 2"><img src="http://192.168.101.152:8848/commonStatic/ckzs/fetusMovement/random-icon.png" v-else>顺序播放</view></view><scroll-view scroll-y style="height: 1050rpx;"><view class="music-list"><view :class="['music-item', current  == index && isPlay ? 'active' : '']"v-for="(item, index) in musicLst":key="index"@click="handleItemClick(index)"><view class="name">{{item.bsmb002}}</view><PlayerAnimation v-if="current == index && isPlay"></PlayerAnimation></view></view></scroll-view></view></tn-popup></template><script>
import PlayerAnimation from "../../../components/player-animation/player-animation.vue";
export default {props: {musicLst : {type: Array,default: []},current: {type: Number,default: 0},toggleType:{type:Number,default: 1},isPlay:{type:Boolean,default: false}},components: {PlayerAnimation},data() {return {show: false}},methods: {// 切换歌曲handleItemClick(index) {this.$emit('handleMusicChange', index);},// 关闭handleClose() {this.show = false;},// 播放类型切换handleToggle() {const playType = this.toggleType == 1 ? 2 : this.toggleType == 2 ? 3 : 1;this.$emit('handleToggleType', playType);},}
}
</script><style scoped lang="scss">
.music-container {padding: 0 30rpx 0;.header-layout {display: flex;justify-content: space-between;align-items: center;margin-top: 10rpx;height: 90rpx;}.header-left {display: flex;align-items: center;font-size: 32rpx;font-weight: 500;color: #333333;line-height: 44rpx;text {font-size: 24rpx;font-weight: 400;color: #666666;line-height: 34rpx;}}.header-right {display: flex;align-items: center;height: 56rpx;background: linear-gradient(135deg, #FF74A2 0%, #FF3370 100%);border-radius: 28rpx;padding: 0 12rpx;font-size: 26rpx;color: white;img {margin-right: 10rpx;width: 26rpx;height: 26rpx;}}
}.music-list {font-size: 28rpx;color: #333333;line-height: 40rpx;.music-item {display: flex;align-items: center;justify-content: space-between;padding: 20rpx 0;font-size: 28rpx;color: #333333;line-height: 40rpx;}
}.active {color: #FF3370;
}</style>

3、实现也面向效果展示

(1)播放器
在这里插入图片描述
(2)播放器弹窗
在这里插入图片描述
4、实现该功能过程所遇到的问题总结

(1)当一首歌曲播完之后,进度条不更新问题,在网上查看到的方法都是说:该问题是存在的一个bug,解决的方案是我们再代码中要主动的调用paused()方法

this.timers = setTimeout(() => {console.log(this.musicPlayCtx.paused);
}, 200);

(2)当点击暂停播放后,音乐从头播放的问题,解决方案:利用seek()方法使其跳转到指定位置

 this.musicPlayCtx.seek(this.musicCurrentTime + 1);

(3)音乐播放器的地址,含有中文名称,在模拟器上面可以正常播放,手机上面不可以,解决方案:需要将该地址进行编码,编译成编译器可以识别地址

this.currentSrc = encodeURI(mediaUrl+ this.musicDetail.bsmb007);

5、以上代码可以直接粘贴复制到项目即可使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/341122.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ADOV路由和DSR路由matlab对比仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 ADOV路由&#xff08;Ad hoc On-demand Distance Vector Routing&#xff09; 4.2 DSR路由&#xff08;Dynamic Source Routing&#xff09; 5.完整程序 1.程序功能描述 ADOV路由和DSR…

迅为RK3568开发板Android11/12/Linux编译驱动到内核

在平时的驱动开发中&#xff0c;经常需要在内核中配置某种功能&#xff0c;为了方便大家开发和学习&#xff0c;本小 节讲解如何在内核中添加驱动。具体的讲解原理讲解请参考本手册的驱动教程。 Android11 源码如果想要修改内核&#xff0c;可以运行以下命令进行修改: cd ke…

【python】python新年烟花代码【附源码】

欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 新年的钟声即将敲响&#xff0c;为了庆祝这个喜庆的时刻&#xff0c;我们可以用 Python 编写一个炫彩夺目的烟花盛典。本文将详细介绍如何使用 Pygame 库创建一个令人惊叹的烟花效果。 一、效果图&#xff1a; 二…

R730服务器做了raid的硬盘,插在R720上面可以用吗?

环境 戴尔R720 戴尔R730 问题描述 R730服务器做了raid的硬盘&#xff0c;插在R720上面可以用吗&#xff1f; 解决方案 1.直接在 R730服务器做了raid的硬盘&#xff0c;卸下来在插在r720上面使用 &#xff0c;读不到硬盘 2.前往R730服务器上面&#xff0c;去清除RAID配置的…

第二百六十回

文章目录 知识回顾示例代码经验总结 我们在上一章回中介绍了通道相关的内容&#xff0c;本章回中将介绍其中的一种通道&#xff1a;MethodChannnel.闲话休提&#xff0c;让我们一起Talk Flutter吧。 知识回顾 我们在上一章回中介绍了通道的概念和作用&#xff0c;并且提到了通…

GEE查看MODIS的NDVI、EVI产品并生成逐日/逐月NDVI曲线

目录 MOD13Q1MOD09GA计算逐日/逐月NDVI生成曲线参考博文 MOD13Q1 MOD13Q1有两个产品&#xff1a;NDVI和EVI&#xff0c;每16天为全球提供&#xff0c;分辨率为250M 通过查看时间&#xff0c;该NDVI产品是16天一景 MOD09GA 提供逐日的表面反射率产品&#xff0c;分辨率为500m…

计算机网络 物理层

文章目录 物理层物理层的基本概念数据通信的基础知识数据通信系统的模型有关信道的几个基本概念信道的极限容量 物理层下面的传输媒体导引型传输媒体非引导型传输媒体 信道复用技术波分复用码的复用 宽带接入技术ADSL 技术光纤同轴混合网 (HFC 网&#xff09;FTTx 技术 物理层 …

SpringMVC的四种跳转方式

默认的跳转是请求转发&#xff0c;直接跳转到jsp页面展示&#xff0c;还可以使用框架提供的关键字redirect:&#xff0c;进行一个重定向操作&#xff0c;包括重定向页面和重定向action&#xff0c;使用框架提供的关键字forward:&#xff0c;进行服务器内部转发操作&#xff0c;…

【电商API接口】jd.item_search按关键字搜索京东商品返回值和参数说明

item_search-按关键字搜索商品 [查看演示] API测试工具 注册开通 jd.item_search 公共参数 请求地址: 申请调用KEY测试 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08…

vue3中使用ace-builds,并设置自定义代码提示(Echarts 配置项),添加代码格式化功能

首先安装 ace-builds “ace-builds”: “^1.24.0” 代码中 import { keywords } from /editor/data/option-keywords 是自定义的代码提示配置文件 自定义代码提示文件内容如下图&#xff1a; 其实还可以添加一个代码格式化插件。 import beautify from js-beautify; “js-bea…

概率论与数理统计-第6章 参数估计

6.1 点估计问题概述 一、点估计的概念 二、评价估计量的标准 无偏性 定义1&#xff1a;设^ θ(X1,…,Xn)是未知参数θ的估计量&#xff0c;若E(^ θ)θ,则称^θ为θ的无偏估计量定理1&#xff1a;设X1,…,Xn,为取自总体X的样本&#xff0c;总体X的均值为μ&#xff0c;方差为…

【Python学习】Python学习14-函数

目录 【Python学习】Python学习14-函数 前言自定义函数创建语法自定义函数与调用参数传递参考 文章所属专区 Python学习 前言 本章节主要说明Python的函数。函数是组织好的&#xff0c;可重复使用的&#xff0c;用来实现单一&#xff0c;或相关联功能的代码段。 函数能提高应…