在线预览传送门:http://iblossomspace.com/onlineMusicPlayer
本项目仅作学习交流使用,歌曲版权归QQ音乐所有!
相关技术栈:react.js
+ react-router-dom
+ redux
使用到的第三方 react 组件:swiper
+ react-scrollbar
使用 redux 管理当前正在播放的歌曲、播放列表、播放历史、收藏的歌曲数据。
在路由跳转的多个页面中都需要获取以上数据,为了避免将数据在组件树上自上而下层层传递,再自下而上层层传递的繁复操作,此处使用 redux 管理以上数据。
redux 具体使用方法在此不做赘述了。
自定义滚动条的 react 组件有很多,此处我选择了 react-scrollbar ,该组件满足滚动条的滚动、拖拽、点击需求。
在歌曲播放进度更新,需要同步移动歌词区域的滚动条时,需要使用该组件提供的 scrollYTo(topPosition)
方法。根据 npm 官网上该组件的文档描述,该方法挂载在组件实例的 context
属性的 scrollArea
对象下,由于 react.js 的更新使得 context
相关的API有明显差异,而该组件是基于旧版本的 context
API 进行封装的,始终无法根据文档提示的方法获取。
虽然如此,但是通过 ref
获取组件实例后发现,组件实例下就存在 scrollArea
这个对象,自然也能使用 scrollArea
下面的那些API了。
this._scrollArea=scrollArea}
>
this._scrollLyrics.scrollArea.scrollYTo(34 * (this.state.currentIndex - 4))
根据以下顺序请求接口并保证每次渲染顺序一致。在整个实践中,我使用了fetch
来请求数据。
// 首页推荐歌单
export const homeSheet = [
{ name: "流行音乐", id: 4 },
{ name: "热门歌曲", id: 26 },
{ name: "最新音乐", id: 27 },
{ name: "网络歌曲", id: 28 }
];
使用 Promise.all()
方法进行封装,结合 fetch
,请求到的数据依次请求完并按照顺序存入数组后,再使用 setState
更新视图数据。
// 获取分类歌单
getSheets = async () => {
const resArr = await Promise.all((function () {
const fetches = [];
homeSheet.forEach(item => {
fetches.push(fetch(api.topid + item.id))
})
return fetches;
})());
const dataArr = await Promise.all((function () {
const datas = [];
resArr.forEach(item => {
datas.push(item.json());
})
return datas;
})());
const sheets = [];
dataArr.forEach((item, index) => {
sheets.push({
id: homeSheet[index].id,
name: homeSheet[index].name,
songs: item.songs
})
})
this.setState({ sheets })
}
不过,这样便降低了性能,每次载入首页都较为耗时。
同时,若在组件 setState
数据渲染完成前就切换到其它路由页面,则会报错(因为还有 setState
这个异步操作未完成,提示建议在 componentWillUnmount
这个钩子函数中取消操作)。
此处我为了解决报错提示,直接显示 Loading 组件遮罩在最上层,等待视图中的数据异步渲染完成后再隐藏 Loading 组件。但是因操作耗时 Loading 组件显示的时间略微有些长。
此处暂待优化。
文中所述若有不当之处,敬请批评指正,谢谢!