基于 React 实现的仿 iOS 客户端网易云音乐。css
项目地址:戳我react
在线地址:戳我(PC 浏览器需切换到移动端模式)git
移动端体验:github
目前只实现了上面四个页面,可是整体的结构已经造成了,其余页面的添加只是时间上的问题 (实际上是懒),暂时没有实现,下面是目前已实现的功能的细节:redux
像首页的 banner 或者推荐歌单等,都是不会被共享的局部状态,使用 Mobx 来进行请求的发起和状态的管理。api
播放器的状态是一个全局状态,包括当前的播放列表,切歌,播放 / 暂停等,因此很天然的使用 redux 来进行管理,能够清楚的掌握全部改变全局状态的行为。浏览器
尽管上手须要掌握一些语法,可是静态类型与自动提示都能提供很大的帮助,在这个并不大的项目中我也体验到了很大的帮助。可是要注意的是 TS 其实并不严格限制对象的类型,只要够懒,遍地 any,就会把 TS 写成 JS,因此为了充分发挥 TS 的威力,必定要有良好的 TS 代码风格。react-router
为了模仿 iOS 端能够经过滑屏切换页面的功能,经过监听 touchStart
,touchMove
,touchEnd
来进行手势的判断并经过 transform
触发模拟滚动实现,在 touchMove
中检测监听滑动的方向及距离,在 touchEnd
中触发路由的切换及页面吸附到整屏的位置。code
有这么一个操做须要注意:用户在某歌单往下滑了几下,而后点了某歌播放而后进入了播放器,会发生路由的改变,若是此时从播放器返回,会丢包包括滚动位置在内的歌单页的全部状态丢失(由于 re-mount 了)。orm
我造了一个轮子来解决这个问题:react-live-route,是对 react-router-v4 中 Route 组件的加强,简单的说就是将歌单页隐藏掉而不是 unmount 掉,具体的解决思路能够参考轮子里的文档。
在 iOS 版的网易云中,能够滑动来切换页面,同时会触发顶部 tab 下的滑块移动。在项目中,滑动页面与滑块分属于两个兄弟组件的子组件且嵌套层次较深,若是直接经过 prop 来传递略显丑陋,有以下解决方案:
经过 redux,可是 redux 最好只负责领域数据,这种 UI 的状态就不要往 store 中放了。
经过 event-emitter,其实和 redux 差很少,由于 redux 也是基于 event-emitter 实现的, 可是不通过 react-redux 虽然能够实现,可是破坏了 react 整个自顶向下界面更新的原则。
经过新的 context API 实现,以下图:
项目中用到的网易云音乐的 API 来自 NeteaseCloudMusicApi。
目前还有一些部分没完成,包括但不限于:
克隆代码到本地以后,须要在 4000 端口运行 NeteaseCloudMusicApi。
项目地址:戳我