后端基于开源的 网易云音乐接口 ,前端基于React+Ant Design实现的web端应用
项目已经完成大部分页面展示与功能实现
项目预览地址: 点我点我
项目仅作学习与交流
包含轮播图、热门推荐、榜单等
1![]() |
2![]() |
---|
![]() |
![]() |
---|
包含歌词展示、歌词展开收起等功能
1![]() |
2![]() |
---|
包含排行榜数据展现、切换排行榜等功能
1![]() |
2![]() |
---|
包含分类选择、歌单卡片展示、分页等功能
1![]() |
2![]() |
---|
由于页面较多涉及组件复用、数据展示等相同功能、展示,因此统一展示
1![]() |
2![]() |
---|---|
1![]() |
2![]() |
1![]() |
2![]() |
页面内容展现较完善,但仍有一些功能没有实现,因此作出补充说明。搜索功能还没实现,登录功能还没实现,同时页面目前仅支持在 发现音乐-推荐 里的榜单处点击播放另外歌曲,这些功能仍待完善,欢迎大家进行补充完善。
复杂数据页面展示
项目涉及比较多的页面布局和对请求到的数据进行处理展示,页面布局有些比较麻烦的地方和组件复用中的一些问题,这需要花费相当的时间进行样式布局和逻辑处理。
歌曲切换与添加歌曲功能
由于歌曲播放时允许设置三种模式:顺序播放、单曲循环、随机播放,当歌曲播放完时要进行播放判断从而进行不同处理,当手动添加新歌曲时,首先在歌曲播放列表中进行寻找,若没有则添加歌曲进入播放列表中,若歌曲播放列表中存在歌曲则切换歌曲播放的顺序,涉及比较多的逻辑处理和判断,这里给出部分代码,具体请参考完整项目所示
const changeMusic = (tag) => {
dispatch(changeCurrentIndexAndSongAction(tag))
}
const handleMusicEnded = () => {
if(sequence === 2){ //单曲循环
audioRef.current.current = 0
audioRef.current.play()
}else{
dispatch(changeCurrentIndexAndSongAction(1))
}
}
export const changeCurrentIndexAndSongAction = (tag) => {
return (dispatch, getState) => {
const playList = getState().getIn(["player", "playList"])
const sequence = getState().getIn(["player", "sequence"])
let currentSongIndex = getState().getIn(["player", "currentSongIndex"])
switch (sequence) {
case 1: // 随机播放
let randomIndex = Math.floor(Math.random() * playList.length)
while (randomIndex === currentSongIndex) {
randomIndex = Math.floor(Math.random() * playList.length)
}
currentSongIndex = randomIndex
break;
default: //循序播放
currentSongIndex = currentSongIndex + tag
if (currentSongIndex >= playList.length) {
currentSongIndex = 0
}
if (currentSongIndex < 0) {
currentSongIndex = playList.length - 1
}
}
const currentSong = playList[currentSongIndex]
dispatch(changeCurrentSongAction(currentSong))
dispatch(changeCurrentSongIndexAction(currentSongIndex))
dispatch(getLyricAction(currentSong.id))
}
}
拖拉歌曲进度条时关联的动态变化
由于是手动实现的歌曲播放控制面板,拖拉滑动条时歌曲播放进度(声音)、歌曲时间与歌词当然不会实现动态变化,歌曲播放进度(声音)的动态改变由audio元素的currentTime属性决定,歌曲时间的动态改变由滑动条回调时的value属性决定,歌词的动态变化由对歌词接口返回数据进行的逻辑判断决定,涉及比较多的逻辑处理和判断,这里给出部分代码,具体请参考完整项目所示
// 滑动条拖动时发生的回调
const slideChange = useCallback((value) => {
setIsChanging(true)
// 随着拖动,当前时间发生更改
const currentTime = value / 100 * duration / 1000
setCurrentTime(currentTime * 1000)
setProgess(value)
}, [duration])
// 滑动条结束拖动时发生的回调
const slideAfterChange = useCallback((value) => {
const currentTime = value / 100 * duration / 1000
audioRef.current.currentTime = currentTime
setCurrentTime(currentTime * 1000)
setIsChanging(false)
if(!isPlaying){
playMusic()
}
}, [duration, isPlaying, playMusic])
const timeUpdate = (e) => {
const currentTime = e.target.currentTime
if (!isChanging) {
setCurrentTime(currentTime * 1000)
setProgess(currentTime * 1000 / duration * 100)
}
// 获取当前歌词
let index = 0
for (let i=0; i<lyricList.length; i++){
let lyricItem = lyricList[i]
if(lyricItem.time > currentTime * 1000){
index = i - 1
break
}
}
// console.log();
if (currentLyricIndex !== index) {
dispatch(changeCurrentLyricIndexAction(index))
let content = lyricList[index] && lyricList[index].content
message.open({
key: "lyric",
content: content,
duration: 0,
className: "lyric-class"
})
}
}
clone项目:
git clone https://gitee.com/junjiangLi/ljmusic.git
安装项目依赖:
yarn
项目运行:
yarn start
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。