uni-app中实现音乐播放器
1、主要利用的是uni-app中提供的uni.createInnerAudioContext()来进行实现;
2、代码示例
(1)主页面代码展示
<template><view class="songDetailContainer"><view class="bg" :style="{ backgroundImage: `url(${song.imageUrl})` }"></view><view class="content"><view class="title">{{ song.title }}</view><view class="discContainer discAnimation" v-show="current == 0"><view class="disc"></view><view class="circle"><image class="musicImg" :src="song.imageUrl"></image></view></view><scroll-viewclass="h-full":scroll-y="true":refresher-enabled="false":scroll-anchoring="true"v-show="current == 1"><view class="prompt" v-html="song.lyric" style="white-space: pre-line"> </view></scroll-view><u-tabsclass="u-tabs-con":list="list1"@change="handleChange":current="current":scrollable="true"active-color="#fff"inactive-color="#ccc4c2":gutter="20":bar-width="20"></u-tabs><view class="share"><u-icon name="share" color="#fff" size="40" @click="shareClick"></u-icon><text> 分享 </text></view><!-- 进度条控制区域 --><view class="progressControl"><text>{{ currentTimeText }}</text><sliderstyle="width: 560rpx"@change="handleSliderChange":value="sliderIndex":max="maxSliderIndex"activeColor="#ea588e"backgroundColor="#b9c2c5"block-color="#fff"block-size="12"/><text>{{ totalTimeText }}</text></view><!-- 底部控制播放区域 --><view class="musicControl"><u-icon name="star" color="#fff" size="60" @click="starClick"></u-icon><u-iconname="rewind-left-fill"@click="handlePrev"color="#fff"size="60"id="pre"></u-icon><u-iconname="pause-circle-fill"@click="onPauseAudio"v-if="isPlay"color="#fff"size="80"></u-icon><u-iconname="play-circle-fill"@click="onPlayAudio"v-elsecolor="#fff"size="80"></u-icon><u-iconname="rewind-right-fill"@click="handleNext"color="#fff"size="60"id="next"></u-icon><u-icon name="grid" @click="show = true" color="#fff" size="60"></u-icon></view></view></view><u-action-sheetclass="action-sheet":list="data.list"v-model="show"@click="sheetClick"cancel-text="关闭"></u-action-sheet><!-- #ifdef H5 -->
</template><script lang="ts" setup>
import { ref, reactive, onUnmounted } from 'vue'
import moment from 'moment'
import { onLoad } from '@dcloudio/uni-app'
import { download } from '@/utils/download'
import { drawingRecord } from '@/api/music'
let id = ref(0) // 歌曲详情对象
const song = ref({}) // 歌曲详情对象
const isPlay = ref(false) // 音乐是否播放
const currentTime2 = ref(0) // 实时时间
const audioList = ref([]) // 音乐列表
let index = 0
const show = ref(false)
const innerAudioContext = uni.createInnerAudioContext()
const startId = ref(0)
const endId = ref(0)
const sliderIndex = ref(0) //滑块当前值
const maxSliderIndex = ref(100) //滑块最大值
const currentTimeText = ref('00:00') //视频已播放长度文字
const totalTimeText = ref('00:00') //视频总长度文字
onLoad((options: any) => {id.value = options.idstartId.value = options.startIdendId.value = options.endIdgetAudioList()})
const getAudioList = async () => {const { lists } = await drawingRecord({status: 3,startId: startId.value,endId: endId.value,pageNo: 1,pageSize: 100})audioList.value = listsfor (let i = 0; i < audioList.value.length; i++) {if (audioList.value[i].id == id.value) {index = iconsole.info('index', i)}}song.value = audioList.value[index]innerAudioContext.autoplay = trueinnerAudioContext.src = song.value.audioUrlinnerAudioContext.play()isPlay.value = true
}innerAudioContext.onEnded(() => {isPlay.value = falsecurrentTimeText.value = '00:00'sliderIndex.value = 0handleNext()
})
innerAudioContext.onTimeUpdate(() => {currentTimeText.value = moment(innerAudioContext.currentTime * 1000).format('mm:ss')sliderIndex.value = innerAudioContext.currentTime
})
innerAudioContext.onCanplay(function () {totalTimeText.value = moment(innerAudioContext.duration * 1000).format('mm:ss')maxSliderIndex.value = innerAudioContext.duration
})innerAudioContext.onPause(() => {currentTime2.value = innerAudioContext.currentTime
})
innerAudioContext.onPlay(() => {innerAudioContext.seek(currentTime2.value)console.log(currentTime2.value, 'currentTime2.value')
})const onPauseAudio = () => {innerAudioContext.pause()isPlay.value = false
}
const onPlayAudio = () => {innerAudioContext.src = song.value.audioUrlinnerAudioContext.play()isPlay.value = true
}const handlePrev = () => {innerAudioContext.stop()sliderIndex.value = 0currentTimeText.value = '00:00'currentTime2.value = 0if (index == 0) {index = audioList.value.length}innerAudioContext.src = audioList.value[index - 1].audioUrlsong.value.title = audioList.value[index - 1].titlesong.value.imageUrl = audioList.value[index - 1].imageUrlsong.value.duration = audioList.value[index - 1].durationsong.value.lyric = audioList.value[index - 1].lyricinnerAudioContext.play()isPlay.value = trueindex -= 1console.log(index, 'index')
}
const handleNext = () => {innerAudioContext.stop()sliderIndex.value = 0currentTimeText.value = '00:00'currentTime2.value = 0console.log(sliderIndex.value, currentTimeText.value, '下一首')if (index == audioList.value.length - 1) {index = -1}innerAudioContext.src = audioList.value[index + 1].audioUrlsong.value.title = audioList.value[index + 1].titlesong.value.imageUrl = audioList.value[index + 1].imageUrlsong.value.duration = audioList.value[index + 1].durationsong.value.lyric = audioList.value[index + 1].lyricinnerAudioContext.play()isPlay.value = trueindex += 1console.log(index, 'index')
}// 文件下载
const onFileDownload = async (drawing: any) => {uni.setClipboardData({data: drawing,success: function () {uni.showToast({ title: '复制成功,请打开浏览器下载', duration: 2000 })}})
}const data = reactive({list: [{text: '下载音频',fontSize: 28},{text: '下载视频',fontSize: 28}]
})
const sheetClick = (index: number) => {if (index == 0) {onFileDownload(song.value.audioUrl)} else if (index == 1) {onFileDownload(song.value.videoUrl)}
}
//变更滑块位置
const handleSliderChange = (e) => {changePlayProgress(e.detail ? e.detail.value : e)
}
//更改播放进度
const changePlayProgress = (value: any) => {sliderIndex.value = valueinnerAudioContext.seek(value)currentTimeText.value = moment(value * 1000).format('mm:ss')
}
// tabs部分
const current = ref(0)
const list1 = ref([{ customMode: 0, name: '歌曲' },{ customMode: 1, name: '歌词' }
])const handleChange = (index: number) => {current.value = index
}
const starClick = () => {uni.showToast({ title: '敬请期待' })
}
const shareClick = () => {uni.showToast({ title: '敬请期待' })
}
onUnmounted(() => {innerAudioContext.destroy()
})
</script><style lang="scss" scoped>
.songDetailContainer {height: 100vh;width: 100%;position: relative;.bg {width: 100%;height: 100vh;position: absolute;z-index: 0;background-size: cover;background-repeat: no-repeat;filter: blur(60px);}.content {display: flex;justify-content: space-around;flex-direction: column;align-items: center;.title {color: #fff;position: absolute;top: 30rpx;}.prompt {color: #fff;position: absolute;top: 80rpx;left: 40rpx;right: 40rpx;font-size: 38rpx;line-height: 68rpx;}.h-full {position: absolute;top: 120rpx;left: 40rpx;right: 40rpx;height: 800rpx;width: calc(100% - 80rpx);}.u-tabs-con {position: absolute;bottom: 300rpx;color: #fff;}}
}
.content ::v-deep .u-tabs {background: none !important;
}
.share {position: absolute;bottom: 320rpx;right: 50rpx;color: #fff;display: flex;align-items: center;text {margin-left: 10rpx;font-size: 24rpx;}
}
/* 磁盘 */
.discContainer {position: relative;top: 200rpx;// width: 598rpx;// height: 598rpx;width: 490rpx;height: 490rpx;border: 1rpx solid #e6e6e6;border-radius: 50%;
}.discAnimation {animation: disc 8s linear infinite;animation-delay: 1s;
}/*@keyframes: 设置动画帧1) from to- 使用于简单的动画,只有起始帧和结束帧- 北京 - 上海 直达2) 百分比- 多用于复杂的动画,动画不止两帧- 北京 - 上海 ---> 北京 -- 天津 --- 深圳 --- 上海- 0% - 100%, 可以任意拆分
*/
@keyframes disc {from {transform: rotate(0deg);}to {transform: rotate(360deg);}
}.disc {width: 100%;height: 100%;
}.songDetailContainer .discContainer .musicImg {position: absolute;left: 0;right: 0;top: 0;bottom: 0;margin: auto;width: 370rpx;height: 370rpx;border: 1rpx solid transparent;border-radius: 50%;
}
.circle {position: absolute;left: 30rpx;top: 30rpx;width: 430rpx;height: 430rpx;border: 1rpx solid #e6e6e6;border-radius: 50%;
}
/* 底部控制播放区域 */
.musicControl {position: absolute;bottom: 80rpx;left: 60rpx;width: calc(100% - 120rpx);display: flex;justify-content: space-between;
}
.musicControl text {width: 20%;height: 120rpx;line-height: 120rpx;text-align: center;color: #fff;font-size: 50rpx;
}
.musicControl text.big {font-size: 80rpx;
}
/* 进度条控制区域 */
.progressControl {position: absolute;bottom: 200rpx;width: 640rpx;height: 80rpx;line-height: 80rpx;display: flex;color: #fff;
}.action-sheet ::v-deep .u-action-sheet-item {align-items: baseline;padding-left: 30rpx;
}
</style>