_uniapp 音乐播放器">
赞
踩
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-view
class="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-tabs
class="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>
<slider
style="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-icon
name="rewind-left-fill"
@click="handlePrev"
color="#fff"
size="60"
id="pre"
></u-icon>
<u-icon
name="pause-circle-fill"
@click="onPauseAudio"
v-if="isPlay"
color="#fff"
size="80"
></u-icon>
<u-icon
name="play-circle-fill"
@click="onPlayAudio"
v-else
color="#fff"
size="80"
></u-icon>
<u-icon
name="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-sheet
class="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.id
startId.value = options.startId
endId.value = options.endId
getAudioList()
})
const getAudioList = async () => {
const { lists } = await drawingRecord({
status: 3,
startId: startId.value,
endId: endId.value,
pageNo: 1,
pageSize: 100
})
audioList.value = lists
for (let i = 0; i < audioList.value.length; i++) {
if (audioList.value[i].id == id.value) {
index = i
console.info('index', i)
}
}
song.value = audioList.value[index]
innerAudioContext.autoplay = true
innerAudioContext.src = song.value.audioUrl
innerAudioContext.play()
isPlay.value = true
}
innerAudioContext.onEnded(() => {
isPlay.value = false
currentTimeText.value = '00:00'
sliderIndex.value = 0
handleNext()
})
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.audioUrl
innerAudioContext.play()
isPlay.value = true
}
const handlePrev = () => {
innerAudioContext.stop()
sliderIndex.value = 0
currentTimeText.value = '00:00'
currentTime2.value = 0
if (index == 0) {
index = audioList.value.length
}
innerAudioContext.src = audioList.value[index - 1].audioUrl
song.value.title = audioList.value[index - 1].title
song.value.imageUrl = audioList.value[index - 1].imageUrl
song.value.duration = audioList.value[index - 1].duration
song.value.lyric = audioList.value[index - 1].lyric
innerAudioContext.play()
isPlay.value = true
index -= 1
console.log(index, 'index')
}
const handleNext = () => {
innerAudioContext.stop()
sliderIndex.value = 0
currentTimeText.value = '00:00'
currentTime2.value = 0
console.log(sliderIndex.value, currentTimeText.value, '下一首')
if (index == audioList.value.length - 1) {
index = -1
}
innerAudioContext.src = audioList.value[index + 1].audioUrl
song.value.title = audioList.value[index + 1].title
song.value.imageUrl = audioList.value[index + 1].imageUrl
song.value.duration = audioList.value[index + 1].duration
song.value.lyric = audioList.value[index + 1].lyric
innerAudioContext.play()
isPlay.value = true
index += 1
console.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 = value
innerAudioContext.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>
npm i moment
/**
* @description 下载文件
* @param {String} url 文件url
* @param {String} name 下载的文件名称
*/
export const download = (url: string, name: string) => {
const aTag = document.createElement('a')
document.body.appendChild(aTag)
aTag.href = url
aTag.download = name
aTag.click()
aTag.remove()
}
{
"code": 200,
"msg": "成功",
"data": {
"count": 34,
"pageNo": 1,
"pageSize": 10,
"extend": null,
"lists": [
{
"id": 1735,
"userId": 37,
"type": "q_avatar",
"prompt": null,
"uploadImageUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/image/20240702/1b4fb4e0-d6bd-492a-8cce-81228bb39d43.png",
"imageUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/draw_face/20240702/e1a39823-b170-4583-bd3f-203c843c75cd.png",
"videoUrl": "",
"taskId": "faff5f904a3a473b9fa3c911b5a3b646",
"useTokens": 6,
"failReason": null,
"status": 3,
"createTime": "2024-07-02 23:51:16",
"updateTime": null
},
{
"id": 1734,
"userId": 37,
"type": "q_avatar",
"prompt": null,
"uploadImageUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/image/20240702/7e9a1aca-323d-4b7a-b1c4-e9758f05bde9.png",
"imageUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/draw_face/20240702/4f11e627-eedb-41be-a0b5-b23341b07f90.png",
"videoUrl": "",
"taskId": "5e0aeaa128454e55bd4da1aa7ec4c294",
"useTokens": 6,
"failReason": null,
"status": 3,
"createTime": "2024-07-02 23:46:54",
"updateTime": null
},
{
"id": 1733,
"userId": 37,
"type": "q_avatar",
"prompt": null,
"uploadImageUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/image/20240702/aa589a1b-6075-40b7-b2aa-633566cebfd1.png",
"imageUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/draw_face/20240702/fc1f375e-2267-4cfe-a90a-605132251559.png",
"videoUrl": "",
"taskId": "4ab6c962d468447aa3bb85a0e668b322",
"useTokens": 6,
"failReason": null,
"status": 3,
"createTime": "2024-07-02 23:40:53",
"updateTime": null
},
{
"id": 1729,
"userId": 37,
"type": "text_to_video",
"prompt": "You really are beautiful.",
"uploadImageUrl": "",
"imageUrl": null,
"videoUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/draw_video/20240702/f543ad64-15ab-48ae-b5ca-2c4ab1025ef6.mp4",
"taskId": "44d7daf9b7b7476985f235097e4f093c",
"useTokens": 6,
"failReason": null,
"status": 3,
"createTime": "2024-07-02 21:28:12",
"updateTime": null
},
{
"id": 1710,
"userId": 37,
"type": "text_to_video",
"prompt": "Hahaha!",
"uploadImageUrl": "",
"imageUrl": null,
"videoUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/draw_video/20240630/1119796d-ea46-4153-a2c2-11c35ce2e556.mp4",
"taskId": "79561f5cd8ec4a1fbd6b8d8b0be3742c",
"useTokens": 6,
"failReason": null,
"status": 3,
"createTime": "2024-06-30 08:40:36",
"updateTime": null
},
{
"id": 1708,
"userId": 37,
"type": "text_to_video",
"prompt": "女孩: girl",
"uploadImageUrl": "",
"imageUrl": null,
"videoUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/draw_video/20240627/2cab90df-5e16-4a94-a008-306cae2c10ab.mp4",
"taskId": "4a72dd149f784a2db66314bc8eb2cf3d",
"useTokens": 6,
"failReason": null,
"status": 3,
"createTime": "2024-06-27 11:38:01",
"updateTime": null
},
{
"id": 1699,
"userId": 37,
"type": "text_to_video",
"prompt": "A young boy adventurer, adventuring, explorer, outdoors, nature, hiking, backpacking, camping, mountains, forests, wilderness, curiosity, exploration, journeys, discoveries, travels, wanderlust, exploring, pioneer, energetic, proactive, fearless, brave, curious, imaginative, creative, independent, outdoorsy, passionate about nature, discovery, seeking thrills. A boy with a mischievous free spirit, raw and wilderness explorer, a young adventurer, a backpacker training for his journey, an adventuring youth growing up and becoming a dedicated outdoorsman and nature lover. Masterpieces of the highest quality and best possible craftsmanship. Close-ups.",
"uploadImageUrl": "",
"imageUrl": null,
"videoUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/draw_video/20240625/082bfbf8-372b-483c-98d9-7141e406c34d.mp4",
"taskId": "93edbaf942604c5cbbf7d781936f029f",
"useTokens": 6,
"failReason": null,
"status": 3,
"createTime": "2024-06-25 14:02:57",
"updateTime": null
},
{
"id": 1698,
"userId": 37,
"type": "text_to_video",
"prompt": "Young adventurer, adventure, explorer, outdoors, nature, hiking, backpacking, camping, mountains, forests, wilderness, curiosity, exploration, journey, discovery, travel, nomadism, pioneer, youthful, energetic, positive, fearless, brave, curious, imaginative, creative, independent, outdoorsy, nature lover, seeking thrills, boy, mischievous, free spirit, rugged, wilderness explorer, young adventurer, backpacker, training explorer, growing adventurer, outdoor enthusiast. Masterpiece, high quality, best quality, close-up.",
"uploadImageUrl": "",
"imageUrl": null,
"videoUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/draw_video/20240625/36b3dbd0-b523-4311-869d-1624eaae4519.mp4",
"taskId": "5e84d4fda9b746b6b379e6ccde7a218c",
"useTokens": 6,
"failReason": null,
"status": 3,
"createTime": "2024-06-25 14:02:28",
"updateTime": null
},
{
"id": 1697,
"userId": 37,
"type": "text_to_video",
"prompt": "Fighter jet.",
"uploadImageUrl": "",
"imageUrl": null,
"videoUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/draw_video/20240623/715470ef-d3fa-48b8-a360-286d9c62ea47.mp4",
"taskId": "e35df5a8932c4df7801694693020fd37",
"useTokens": 6,
"failReason": null,
"status": 3,
"createTime": "2024-06-23 21:53:00",
"updateTime": null
},
{
"id": 1696,
"userId": 37,
"type": "text_to_video",
"prompt": "The combat effectiveness of F30",
"uploadImageUrl": "",
"imageUrl": null,
"videoUrl": "http://zhcs1.oss-cn-shanghai.aliyuncs.com/draw_video/20240623/d5dc2628-65f7-4c58-b5f3-f0057571d1f4.mp4",
"taskId": "441d9a104bb244fdb7e7f50490155c13",
"useTokens": 6,
"failReason": null,
"status": 3,
"createTime": "2024-06-23 21:52:19",
"updateTime": null
}
]
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。