提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
1、本文记录一下自己在学习uniapp中遇到的问题,在使用ref获取dom节点时发现并不可以于是换用css实现歌词的滚动。
一、大致效果
二、使用步骤
1.歌词详情页代码块
代码如下(示例):
<!-- 歌词详情界面 --> <template> <view class="music-filter" :style="{backgroundImage:'url('+usePlayer.playerList.song.imgurl+')'}" /> <view class="music-detail"> <view class="detail-header"> <u-icon name="arrow-left" class="arrow-left" @click="goBack(1)" color="#707070" size="22" /> <text>{{usePlayer.playerList.song.name}}({{usePlayer.playerList.song.author}})</text> </view> <view class="music-lyc mar-b-24" ref="musicLyc" :style="{top:top+'px'}"> <view :style="{transform:'translateY('+ height + 'px)'}"> <view class="lyc-name">歌曲 : {{usePlayer.playerList.song.name}}</view> <view class="lyc-author"> <text>歌手 : {{usePlayer.playerList.song.author}}</text> </view> <view class="lyc"> <view class="over" v-for="(lyc,index) in lycArr" :key="index" :class="{active:(usePlayer.playerList.musicCurrentTime *1000>=lyc.time && usePlayer.playerList.musicCurrentTime *1000<lyc.pre)}"> {{lyc.lrc}} </view> </view> </view> </view> <!-- 进度条 --> <view class="progress"> <slider min="0" :max="usePlayer.playerList.maxTime" block-size="12" activeColor="#000" backgroundColor="#999" :value="usePlayer.playerList.percentage" @change="move" /> <view class="progress-time"> <view>{{getMusicTime(usePlayer.playerList.musicCurrentTime)}}</view> <view>{{getMusicTime(usePlayer.playerList.musicEndTime)}}</view> </view> </view> <view class="music-operation"> <view @click="usePlayer.playLoopMusic(0)" v-if="!usePlayer.playerList.loop" class="t-icon t-icon-bofang-xunhuanbofang" /> <view @click="usePlayer.playLoopMusic(1)" class="t-icon-suijibofang t-icon" v-else /> <view @click="playTab('pre')" class="t-icon t-icon-bofang-shangyige" /> <view @click="changeStaus(0)" class="t-icon-plays t-icon-ziyuan" v-if="usePlayer.playerList.isPlay" /> <view @click="changeStaus(1)" class="t-icon-plays t-icon-zanting" v-else /> <view @click="playTab('next')" class="t-icon t-icon-bofang-xiayige" /> <view class="t-icon t-icon-shunxubofang" /> </view> </view> </template> <script setup> import { ref, onMounted, onBeforeMount, watch } from 'vue' import { getSongUrl } from '@/api/songList.js' import { onLoad } from "@dcloudio/uni-app" import { goBack, getMusicTime } from '@/utils/hook.js' import { usePlayerStore } from '@/store/index.js' const usePlayer = usePlayerStore() const currentTime = ref(0) const lycArr = ref([]) // 处理歌词 const lyric = () => { let arr if (usePlayer.playerList.song.lyc) { arr = usePlayer.playerList.song.lyc.split(/[(\r\n)\r\n]+/).map((item, i) => { let min = item.slice(1, 3) let sec = item.slice(4, 6) let mill = item.slice(7, 10) let lrc = item.slice(11, item.length) let time = parseInt(min) * 60 * 1000 + parseInt(sec) * 1000 + parseInt(mill) if (isNaN(Number(mill))) { mill = item.slice(7, 9) lrc = item.slice(10, item.length) time = parseInt(min) * 60 * 1000 + parseInt(sec) * 1000 + parseInt(mill) } return { min, sec, mill, lrc, time } }) } if (arr) { arr.forEach((item, i) => { if (i === arr.length - 1 || isNaN(arr[i + 1].time)) { item.pre = 100000 } else { item.pre = arr[i + 1].time } }); } return arr } onBeforeMount(() => { if (!usePlayer.playerList.isPlay) { getMusicUrls() } lycArr.value = lyric() }) // 暂停或开始音乐 const changeStaus = (type) => { if (!type) usePlayer.innerAudioContext.pause() else usePlayer.innerAudioContext.play() usePlayer.setIsPlay(!usePlayer.playerList.isPlay) } // 拖动滚动条 const move = (e) => usePlayer.setSeekMusic(e.detail.value) // 切换歌曲 const playTab = (type) => { if (type === 'pre') { // 如果当前索引为0点击上一首切换到最后一首 if (usePlayer.playerList.musicIndex === 0) { usePlayer.setMusicIndex(usePlayer.playerList.musicList.length - 1) } else usePlayer.setMusicIndex(usePlayer.playerList.musicIndex - 1) } else { // 如果当前索引为最后一位点击上一首切换到第一首 if (usePlayer.playerList.musicIndex === usePlayer.playerList.musicList.length - 1) { usePlayer.setMusicIndex(0) } else usePlayer.setMusicIndex(usePlayer.playerList.musicIndex + 1) } getMusicUrls() } // 获取歌曲url及歌词 const getMusicUrls = async () => { let id = usePlayer.playerList.song.id usePlayer.getMusicUrl(id) lycArr.value = lyric() } // 监听歌曲是否改变 watch(() => usePlayer.playerList.musicIndex, (newValue, oldValue) => { if (newValue !== oldValue && !usePlayer.playerList.isPlay) getMusicUrls() }) // 实现歌词滚动 const height = ref(0) const top = ref(0) watch(() => usePlayer.playerList.musicCurrentTime, () => { height.value = top.value = 0 let p = document.querySelector('.active') if (p) { if (p.offsetTop > 330) { height.value = top.value = 330 - p.offsetTop } } }) </script> <style lang="scss"> .music-filter { position: absolute; z-index: -1; height: 100vh; width: 100%; top: 70vh; background-color: #fff; filter: blur(200rpx); background-repeat: no-repeat; background-size: 350% 100%; position: fixed; } .music-detail { height: 100vh; width: 100%; padding: 24rpx; box-sizing: border-box; display: flex; flex-direction: column; align-items: center; position: fixed; .detail-header { height: 40rpx; width: 100%; display: flex; align-items: center; color: #707070; text { margin: 0 auto; } } .music-lyc { margin-top: 40rpx; overflow-y: auto; text-align: center; height: 80vh; width: 80%; .lyc-name { font-size: 16px; color: #707070; margin-bottom: 10rpx; padding: 10rpx; } .lyc-author { font-size: 14px; color: #A3A3A3; padding: 10rpx; margin-bottom: 10rpx; } .lyc { width: 100%; height: 80%; view { width: 100%; padding: 10rpx; color: #767676; font-size: 14px; text-align: center; } .active { font-size: 22px; color: #000 } } } .progress { width: 100%; display: flex; flex-direction: column; .progress-time { width: 100%; display: flex; align-items: center; justify-content: space-between; view { padding: 10rpx; } } } .music-operation { margin: 40rpx; width: 100%; display: flex; align-items: center; justify-content: space-between; padding: 0 15rpx; .t-icon { width: 50rpx; height: 50rpx; } .t-icon-plays { width: 85rpx; height: 85rpx; } } } </style>
2.封装到仓库(pinia)的音乐实例
代码如下(示例):
// 导入定义仓库的方法
import {
defineStore
} from 'pinia';
import {
getSongUrl
} from '@/api/songList.js'
// 导入响应式和计算
import {
ref
} from 'vue'
export const usePlayerStore = defineStore("player", () => {
// 全局音乐实例
const innerAudioContext = ref(null)
// 歌曲信息
const playerList = ref({
isPlay: false,
song: {
"lyc": "[00:00.00] 作词 : Savan Kotecha/Peter Svensson/Ilya/Ariana Grande\n[00:01.00] 作曲 : Savan Kotecha/Peter Svensson/Ilya/Ariana Grande\n[00:04.51]Hey\n[00:09.53]I know what I came to do\n[00:11.86]And that ain't gonna change\n[00:14.27]So go ahead and talk your talk\n[00:16.63]Cuz I won't take the bait\n[00:19.10]I'm over here doing what I like\n[00:21.43]I'm over here working day and night\n[00:23.86]If my real ain't real enough\n[00:26.31]I'm sorry for you bae\n[00:28.62]Let's find a light inside our universe now\n[00:33.13]Where ain't nobody keep on holding us down\n[00:37.90]Just come and get it let them say what they say\n[00:42.78]Cuz I'm about to put them all away\n[00:48.15]Focus on me, f-f-focus on me\n[00:52.68]Focus on me, f-f-focus on me\n[00:57.55]Focus on me (Focus), f-f-focus on me (Focus on me)\n[01:02.34]Focus on me (Focus), f-f-focus on me (Focus on me)\n[01:06.80]I can tell you're curious\n[01:09.12]It's written on your lips\n[01:11.81]Ain't no need to hold it back\n[01:14.29]Go head and talk your ****\n[01:16.72]I know you're hoping that I'll react\n[01:19.11]I know you're hoping I'm looking back\n[01:21.52]But if my real ain't real enough\n[01:23.82]Then I don't know what is\n[01:26.28]Let's find a light inside our universe now\n[01:30.87]Where ain't nobody keep on holding us down\n[01:35.53]Just come and get it let them say what they say\n[01:40.34]Cuz I'm about to put them all away\n[01:45.39]Focus on me, f-f-focus on me\n[01:50.14]Focus on me, f-f-focus on me\n[01:54.98]Focus on me (Focus), f-f-focus on me (Focus on me)\n[01:59.78]Focus on me (Focus), f-f-focus on me (Focus on me)\n[02:04.67]1, 2, 3, c'mon girls\n[02:10.80]You're gonna like it\n[02:18.26]Come on, now, now\n[02:22.64]\n[02:26.21]Let's find a light inside our universe now\n[02:30.45]Where ain't nobody keep on holding us down\n[02:35.29]Just come and get it let them say what they say\n[02:40.03]Cuz I'm about to put them all away\n[02:47.54]Focus on me, f-f-focus on me\n[02:52.27]Focus on me, f-f-focus on me\n[02:57.04]Focus on me (Focus), f-f-focus on me (Focus on me)\n[03:01.79]Focus on me (Focus), f-f-focus on me (Focus on me)\n[03:06.66]Focus on me, f-f-focus on me\n[03:11.37]Focus on me, f-f-focus on me\n[03:16.12]Focus on me (Focus), f-f-focus on me (Focus on me)\n[03:20.98]Focus on me (Focus), f-f-focus on me (Focus on me)\n",
"songUrl": "http://m702.music.126.net/20231231172931/0e4c69f75f09f72910e736fe5f7526ef/jd-musicrep-ts/6a09/2688/9ba3/8dcfa2324f4a28a11e3f83bc087ce549.mp3",
"singerId": 48161,
"id": 36025888,
"name": "Focus",
"imgurl": "https://p2.music.126.net/lFflM8_fYYBzr4YYCmdX3A==/109951166304034425.jpg",
"author": "Ariana Grande"
},
musicIndex: 0,//歌曲索引值
musicList: [],//歌单数组
musicCurrentTime: 0,//歌曲开始时间
musicEndTime: 0,//歌曲总时长
percentage: 0,//歌曲当前时间
loop: false,//循环播放
maxTime: 100,//进度条最大值
})
// 存放歌曲数组
const setMusicList = (arr) => {
playerList.value.musicList = arr
}
// 更新音乐索引index及歌曲信息
const setMusicIndex = (index) => {
playerList.value.musicIndex = index
const { id, author, name, imgurl, lyc } = playerList.value.musicList[index]
playerList.value.song.id = id
playerList.value.song.name = name
playerList.value.song.author = author
playerList.value.song.imgurl = imgurl
playerList.value.song.lyc = lyc
console.log(index, playerList.value.song)
}
// 播放或暂停音乐
const setIsPlay = (val) => {
playerList.value.isPlay = val
}
//更新歌曲时间
const setMusicTime = (type, time) => {
if (type === 'start') {
playerList.value.musicCurrentTime = time
} else {
playerList.value.musicEndTime = time
}
}
// 获取歌曲url及歌词
const getMusicUrl = async (id) => {
let res = await getSongUrl(playerList.value.song.id)
playerList.value.song.songUrl = res.data[0].url
if (innerAudioContext.value) innerAudioContext.value.destroy()
creatAudio(res.data[0].url)
}
// 创建音乐实例
const creatAudio = (url) => {
innerAudioContext.value = uni.createInnerAudioContext() //创建音乐实例
innerAudioContext.value.autoplay = true //设置是否自动播放
innerAudioContext.value.src = url //音频的url
innerAudioContext.value.onPlay(() => {
// 播放监听
setIsPlay(true)
});
innerAudioContext.value.onPause(() => {
// 暂停监听
setIsPlay(false)
});
innerAudioContext.value.onEnded(() => {
// 结束播放监听
setIsPlay(false)
//自动切换事件
if (playerList.value.musicIndex === playerList.value.musicList.length - 1) setMusicIndex(0)
else setMusicIndex(playerList.value.musicIndex + 1)
});
innerAudioContext.value.onTimeUpdate(() => {
const {
currentTime,
duration
} = innerAudioContext.value;
playerList.value.percentage = parseInt(currentTime)
playerList.value.maxTime = parseInt(duration)
setMusicTime('start', currentTime)
setMusicTime('end', duration)
});
}
// 循环播放音乐
const playLoopMusic = (val) => {
if (!val) innerAudioContext.value.loop = playerList.value.loop = true
else {
innerAudioContext.value.loop = playerList.value.loop = false
let index = Math.floor(Math.random() * playerList.value.musicList.length)
}
}
// 拖动音乐
const setSeekMusic = (val) => {
playerList.value.percentage = parseInt(val)
setMusicTime('start', val)
innerAudioContext.value.seek(val)
innerAudioContext.value.play()
}
// 导出
return {
playerList,
setIsPlay,
setMusicList,
setMusicIndex,
setMusicTime,
creatAudio,
innerAudioContext,
playLoopMusic,
setSeekMusic,
getMusicUrl
}
})
总结
本文只做学习记录使用,有任何不对的地方欢迎大佬指正。转载请备注出处。