react-music
本来没打算写网易云音乐的,好像都已经被大家写烂了,不过没办法,暂时想不到其他的可写,加上网易云音乐又有API,还可以基于restful API做一层graphql的处理再提供给前端调用,然后才决定用react写了这个仿app版网易云音乐
技术栈
- react
- react-router
- redux
- react-redux
- react-motion
- better-scroll
- ES6/7
- stylus
- koa
- graphql
实现的功能
- 发现页
- 我的
- 电台页
- 侧边栏
- 歌单内页
- 电台内页
- 搜索页及结果页
- 上一首
- 下一首
- 播放模式切换
- 歌曲删除
- 歌词
- 左右滑切歌
运行
git clone [email protected]:Binaryify/NeteaseCloudMusicApi.git
这是网易云API,因为最新的banner数据已经改了,可以git reset --hard d155a1fc0177e525cb650d239b8a98a8549a85e1
回退到这次提交
cross-env PORT=8080 npm start
首先启动api服务器,需要用8080
端口启动
git clone [email protected]:Kim09AI/react-music.git
# dev模式
# 先启动graphql服务器
$ cd server && npm run dev
# 再回到根目录
$ npm start
# production模式
# 首次build前先执行(因为使用了dll)
$ npm run build:dll
$ npm run build
# 本地以production模式启动服务器
cd server && npm start
预览
线上地址 github地址 移动端预览 还是来几张动图,大概看看
一些细节
路由配置
react并没有像vue那样,可以通过配置routes数组对象,就会帮我们生成好路由,那要是想像vue一样使用,就得自己动手来实现一个了
/**
* 根据路由配置生成相应路由
* @param {array} routeConfig 路由配置
* @param {string} parentPath 父级路由
*/
export function routes(routeConfig, parentPath = '') {
if (!routeConfig || routeConfig.length === 0) {
return null
}
return (
routeConfig.map(route => (
<Route path={parentPath + route.path} key={parentPath + route.path} exact={route.exact} render={(props) => (
<route.component {...props}>
{/* 在父级路由通过 this.props.children 即可添加嵌套路由*/}
{routes(route.routes, parentPath + route.path)}
</route.component>
)} />
))
)
}
调用方式
<Router>
<Switch>
{
routes(routeConfig)
}
<Redirect to="/home" />
</Switch>
</Router>
对应的routeConfig配置
const routeConfig = [
{
path: '/home',
component: Home,
routes: [
{
path: '/',
component: Found,
exact: true
},
{
path: '/mime',
component: Mime
},
{
path: '/radio',
component: Radio
}
]
},
{
path: '/search',
component: Search,
exact: true
},
{
path: '/search/:keywords',
component: Search
},
{
path: '/playlistDetail/:id',
component: PlaylistDetail
},
{
path: '/radioDetail/:rid',
component: RadioDetail
}
]
export default routeConfig
其实主要的还是如何配置嵌套路由,核心是在配置Route时不使用component
,而是使用render
,把嵌套路由作为this.props.children
传进去,然后还要在父级组件添加{this.props.children}
即可
路由懒加载
react不像vue一样,可以在设置Route的component的时候返回一个promise,等resolve后再路由跳转,这里我使用的是通过一个高阶组件,在这个高阶组件的componentDidMount
中去懒加载的
componentDidMount() {
load().then(({ default: component }) => {
this.setState({
Component: component
})
})
}
懒加载主要就是为了更快的加载首屏,但是在react中有这样一个问题,因为不能在component处返回一个promise,一切换路由就会马上跳转到高阶组件,而componentDidMount
时才开始加载真正需要的组件,这样的话要是没加loading
就可能会造成白屏的现象,然后就想到了这种方法,通过prefetch
预取异步chunk,利用浏览器的空闲时间去下载指定的内容,然后缓存起来,这样下次加载时,就直接从缓存中取出来,从而有效降低白屏时间或无白屏时间
<link rel="prefetch" href="/static/js/pagePlaylistDetail.910ef6d3.chunk.js">
这里用了一个插件preload-webpack-plugin
,添加以下配置到config/webpack.config.prod.js
的plugins中即可
new PreloadWebpackPlugin({
rel: 'prefetch'
}),
移动端无法autoplay
刚开始是使用网上广为流传的touchstart
来处理的,在我手机的其他浏览器都是可以的,结果反而是谷歌浏览器不支持,然后换成touchend
就都可以了
友情提示
在手机上安装谷歌浏览器,访问网站后,点击设置,点击添加到主屏幕,就可以像访问app一样在手机上访问项目了,因为create-react-app
已经集成了pwa
,意思就是只要上https就可以使用pwa
的功能了,可以体验一下
react使用的一些总结
主要还是在react-redux的使用了,数据应该保存在state还是全局的store,主要还是看数据需不需要共享,或者是需不需要缓存,不然存在store反而会使问题变得更麻烦
最后
感谢Binaryify
提供的NeteaseCloudMusicApi
欢迎star
或fork
,有问题或有发现bug页欢迎提issues
,写的不好的地方也请大佬指点