{"id":13755318,"url":"https://github.com/MengZhaoFly/wechatApp-netease_cloudmusic","last_synced_at":"2025-05-10T01:30:45.995Z","repository":{"id":124345019,"uuid":"90253998","full_name":"MengZhaoFly/wechatApp-netease_cloudmusic","owner":"MengZhaoFly","description":"小程序模仿——网易云音乐","archived":false,"fork":false,"pushed_at":"2017-05-13T09:59:42.000Z","size":5510,"stargazers_count":200,"open_issues_count":4,"forks_count":56,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-08-04T10:02:20.594Z","etag":null,"topics":["js","wechat-app"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MengZhaoFly.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-05-04T11:11:08.000Z","updated_at":"2024-06-18T15:22:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"fa795ec8-59d0-4d9b-9f75-4b2de4c7f639","html_url":"https://github.com/MengZhaoFly/wechatApp-netease_cloudmusic","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MengZhaoFly%2FwechatApp-netease_cloudmusic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MengZhaoFly%2FwechatApp-netease_cloudmusic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MengZhaoFly%2FwechatApp-netease_cloudmusic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MengZhaoFly%2FwechatApp-netease_cloudmusic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MengZhaoFly","download_url":"https://codeload.github.com/MengZhaoFly/wechatApp-netease_cloudmusic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224900798,"owners_count":17388942,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["js","wechat-app"],"created_at":"2024-08-03T10:00:52.055Z","updated_at":"2024-11-16T09:30:35.340Z","avatar_url":"https://github.com/MengZhaoFly.png","language":"JavaScript","funding_links":[],"categories":["Demo"],"sub_categories":[],"readme":"![](https://img.shields.io/badge/language-js-orange.svg)\r\n![](https://img.shields.io/badge/platform-wechat-lightgrey.svg)\r\n## 初窥\r\n![](https://github.com/MengZhaoFly/wechatApp-netease_cloudmusic/blob/master/results/all.gif)\u003cbr\u003e\r\ntodo:\r\n- [ ] 添加音乐到收藏（最近）列表\r\n- [ ] 歌词滚动\r\n## 从一个hello world开始\r\n微信开发者工具生成 目录如下：\r\n```\r\n.\r\n|-- app.js\r\n|-- app.json\r\n|-- app.wxss\r\n|-- pages     \r\n|   |-- index   # 主页\r\n|   |   |-- index.js\r\n|   |   |-- index.json\r\n|   |   |-- index.wxml\r\n|   |   `-- index.wxss\r\n|   `-- log # 日志页面\r\n|   |   |-- log.js\r\n|   |   |-- log.json\r\n|   |   |-- log.wxml\r\n|   |   `-- log.wxss\r\n`-- utils       # 工具\r\n    `-- util.js\r\n```\r\n大体为:\r\n每一个page即是一个页面文件 ，每个页面有一个js/wxml/wxss/json文件 规定：**描述页面的这四个文件必须具有相同的路径与文件名。**\u003cbr\u003e\r\n全局下同路，为公共的逻辑，样式，配置\u003cbr\u003e\r\n与html不同:用`view text navigator` 代替 `div span a`\r\n\r\n## 开发者文档走马观花\r\n**app.json:** 注册pages window tabBar networkTimeout\u003cbr\u003e\r\n[组件说明](https://mp.weixin.qq.com/debug/wxadoc/dev/component/)\u003cbr\u003e\r\n***.js:** 作为逻辑层 与wxml交互 有着丰富的 \r\n网络，\r\n媒体，\r\n文件，\r\n数据缓存，\r\n位置，\r\n设备，\r\n界面...的api\u003cbr\u003e\r\n[官方文档](https://mp.weixin.qq.com/debug/wxadoc/dev/api/)\u003cbr\u003e\r\n***.wxml:** 数据驱动的视图层 +  微信提供了大量的组件 表单 导航 媒体 ...\r\n## 官方组件不够,weui来凑\r\nweui为小程序提供了 weui.wxcss 但大多是造官方组件的轮子\u003cbr\u003e\r\n这里精选,也算是补充两个常用组件\u003cbr\u003e\r\n**对于小程序没有DOM操作 不熟悉mvvm思想的同学 是个很好的入门**\r\n1. navbar\u003cbr\u003e\r\n![navbar](https://github.com/MengZhaoFly/wechatApp-netease_cloudmusic/blob/master/results/tabbar.gif)\r\n```html\r\n\u003c!-- wxml --\u003e\r\n\u003cview class=\"weui-tab\"\u003e\r\n            \u003cview class=\"weui-navbar\"\u003e\r\n                \u003cblock wx:for=\"{{tabs}}\" wx:key=\"*this\"\u003e\r\n                    \u003cview id=\"{{index}}\" class=\"weui-navbar__item {{activeIndex == index ? 'weui-bar__item_on' : ''}}\" bindtap=\"tabClick\"\u003e\r\n                        \u003cview class=\"weui-navbar__title\"\u003e{{item}}\u003c/view\u003e\r\n                    \u003c/view\u003e\r\n                \u003c/block\u003e\r\n                \u003cview class=\"weui-navbar__slider\" style=\"left: {{sliderLeft}}px; transform: translateX({{sliderOffset}}px); -webkit-transform: translateX({{sliderOffset}}px);\"\u003e\u003c/view\u003e\r\n            \u003c/view\u003e\r\n            \u003cview class=\"weui-tab__panel\"\u003e\r\n                \u003cview class=\"weui-tab__content\" hidden=\"{{activeIndex != 0}}\"\u003e选项一的内容\u003c/view\u003e\r\n                \u003cview class=\"weui-tab__content\" hidden=\"{{activeIndex != 1}}\"\u003e选项二的内容\u003c/view\u003e\r\n                \u003cview class=\"weui-tab__content\" hidden=\"{{activeIndex != 2}}\"\u003e选项三的内容\u003c/view\u003e\r\n            \u003c/view\u003e\r\n \u003c/view\u003e\r\n       \r\n```\r\nblock渲染data里面的四个tabs,slider为激活tab选项时候的表现，panel为内容面板\r\n```js\r\n//js\r\nvar sliderWidth = 96; // 需要设置slider的宽度，用于计算中间位置\r\nPage({\r\n    data: {\r\n        tabs: [\"选项一\", \"选项二\", \"选项三\"],\r\n        activeIndex: 1,\r\n        sliderOffset: 0,\r\n        sliderLeft: 0\r\n    },\r\n    onLoad: function () {\r\n        var that = this;\r\n        wx.getSystemInfo({\r\n            success: function(res) {\r\n                that.setData({\r\n                    sliderLeft: (res.windowWidth / that.data.tabs.length - sliderWidth) / 2,\r\n                    sliderOffset: res.windowWidth / that.data.tabs.length * that.data.activeIndex\r\n                });\r\n            }\r\n        });\r\n    },\r\n    tabClick: function (e) {\r\n        this.setData({\r\n            sliderOffset: e.currentTarget.offsetLeft,\r\n            activeIndex: e.currentTarget.id\r\n        });\r\n    }\r\n});\r\n```\r\n了解mvvm思想的同学不难看出 通过tabs数组渲染出来选项后每次点击获取id 然后通过设置hidden显示或隐藏\r\n\r\n2. searchbar\u003cbr\u003e\r\n![searchbar](https://github.com/MengZhaoFly/wechatApp-netease_cloudmusic/blob/master/results/searchbar.gif)\r\n```html\r\n        \u003cview class=\"weui-search-bar\"\u003e\r\n            \u003cview class=\"weui-search-bar__form\"\u003e\r\n                \u003cview class=\"weui-search-bar__box\"\u003e\r\n                    \u003cicon class=\"weui-icon-search_in-box\" type=\"search\" size=\"14\"\u003e\u003c/icon\u003e\r\n                    \u003cinput type=\"text\" class=\"weui-search-bar__input\" placeholder=\"搜索\" value=\"{{inputVal}}\" focus=\"{{inputShowed}}\" bindinput=\"inputTyping\" /\u003e\r\n                    \u003cview class=\"weui-icon-clear\" wx:if=\"{{inputVal.length \u003e 0}}\" bindtap=\"clearInput\"\u003e\r\n                        \u003cicon type=\"clear\" size=\"14\"\u003e\u003c/icon\u003e\r\n                    \u003c/view\u003e\r\n                \u003c/view\u003e\r\n                \u003clabel class=\"weui-search-bar__label\" hidden=\"{{inputShowed}}\" bindtap=\"showInput\"\u003e\r\n                    \u003cicon class=\"weui-icon-search\" type=\"search\" size=\"14\"\u003e\u003c/icon\u003e\r\n                    \u003cview class=\"weui-search-bar__text\"\u003e搜索\u003c/view\u003e\r\n                \u003c/label\u003e\r\n            \u003c/view\u003e\r\n            \u003cview class=\"weui-search-bar__cancel-btn\" hidden=\"{{!inputShowed}}\" bindtap=\"hideInput\"\u003e取消\u003c/view\u003e\r\n        \u003c/view\u003e\r\n        \u003cview class=\"weui-cells searchbar-result\" wx:if=\"{{inputVal.length \u003e 0}}\"\u003e\r\n            \u003cnavigator url=\"\" class=\"weui-cell\" hover-class=\"weui-cell_active\"\u003e\r\n                \u003cview class=\"weui-cell__bd\"\u003e\r\n                    \u003cview\u003e实时搜索文本\u003c/view\u003e\r\n                \u003c/view\u003e\r\n            \u003c/navigator\u003e\r\n        \u003c/view\u003e\r\n```\r\n一个input输入框+一个搜索label+一个清楚内容的icon + 取消按钮\r\n```js\r\nPage({\r\n    data: {\r\n        inputShowed: false,\r\n        inputVal: \"\"\r\n    },\r\n    showInput: function () {\r\n        this.setData({\r\n            inputShowed: true\r\n        });\r\n    },\r\n    hideInput: function () {\r\n        this.setData({\r\n            inputVal: \"\",\r\n            inputShowed: false\r\n        });\r\n    },\r\n    clearInput: function () {\r\n        this.setData({\r\n            inputVal: \"\"\r\n        });\r\n    },\r\n    inputTyping: function (e) {\r\n        this.setData({\r\n            inputVal: e.detail.value\r\n        });\r\n    }\r\n});\r\n```\r\ninput上面有一层label 通过Page里面状态的改变而操作其wxml状态的改变\u003cbr\u003e\r\n不难体会到：**小程序和Vue**的思想还是挺接近的\r\n## 站在巨人的肩膀上为大佬们提供云音乐api\r\n    ---获取云音乐api\r\n\u003e[巨人的源github项目](https://github.com/Binaryify/NeteaseCloudMusicApi)\u003cbr\u003e\r\n\r\n在此我将他部署到leancloud上\u003cbr\u003e\r\n即可在线访问，免去烦人的本地localhost启动,在线url\u003cbr\u003e\r\nhttp://neteasemusic.leanapp.cn\u003cbr\u003e\r\n调用例子:\u003cbr\u003e\r\nhttp://neteasemusic.leanapp.cn/search?keywords=海阔天空\u003cbr\u003e\r\nhttp://neteasemusic.leanapp.cn/lyric?id=347230\u003cbr\u003e\r\n![搜索结果](https://github.com/MengZhaoFly/wechatApp-netease_cloudmusic/blob/master/results/searchresult.jpg)\r\n具体参考api\u003cbr\u003e\r\n\u003e[详细文档](https://binaryify.github.io/NeteaseCloudMusicApi/#/?id=neteasecloudmusicapi)\u003cbr\u003e\r\n## 一切具备 只欠东风\r\n生成目录\r\n```\r\n.\r\n|-- app.js\r\n|-- app.json\r\n|-- app.wxss\r\n|-- common.js #公用js\r\n|-- images #存放项目图片\r\n|-- style\r\n|   |-- weui.wxss   # 引入weui样式  万一你自己不想写css样式呢\r\n|-- pages\r\n|   |-- find   # 发现音乐\r\n|   |   |-- index.js\r\n|   |   |-- index.json\r\n|   |   |-- index.wxml\r\n|   |   `-- index.wxss\r\n|   |--my   # 我的音乐\r\n|   |   |-- index.js\r\n|   |   |-- index.json\r\n|   |   |-- index.wxml\r\n|   |   `-- index.wxss\r\n|   |--now  # 正在播放\r\n|   |   |-- index.js\r\n|   |   |-- index.json\r\n|   |   |-- index.wxml\r\n|   |   `-- index.wxss\r\n|   |--account   # 账号\r\n|   |   |-- index.js\r\n|   |   |-- index.json\r\n|   |   |-- index.wxml\r\n|   |   `-- index.wxss\r\n|   |-- index   # 主页\r\n|   |   |-- index.js\r\n|   |   |-- index.json\r\n|   |   |-- index.wxml\r\n|   |   `-- index.wxss\r\n|   `-- log # 日志页面\r\n`-- utils       # 工具\r\n    `-- util.js\r\n```\r\n请先在在app.json中注册页面，设置navigation，配置tabbar\u003cbr\u003e\r\n```js\r\n{\r\n  \"pages\":[\r\n    \"pages/find/index\",\r\n    \"pages/my/index\",\r\n    \"pages/now/index\",\r\n    \"pages/account/index\",\r\n    \"pages/index/index\"\r\n  ],\r\n  \"window\":{\r\n    \"backgroundTextStyle\":\"light\",\r\n    \"navigationBarBackgroundColor\": \"#D43C33\",\r\n    \"navigationBarTitleText\": \"网易云音乐\",\r\n    \"navigationBarTextStyle\":\"white\",\r\n    \"backgroundColor\": \"#FBFCFD\"\r\n  },\r\n  \"tabBar\": {\r\n    \"backgroundColor\":\"#2A2C2E\",\r\n    \"color\": \"#a7a7a7\",\r\n     \"selectedColor\": \"#ffffff\",\r\n    \"list\": [{\r\n      \"iconPath\":\"./images/find.png\",\r\n      \"selectedIconPath\":\"./images/find1.png\",\r\n      \"pagePath\":\"pages/find/index\",\r\n      \"text\": \"发现音乐\"\r\n    }, {\r\n      \"iconPath\":\"./images/my.png\",\r\n      \"selectedIconPath\":\"./images/my1.png\",\r\n      \"pagePath\": \"pages/my/index\",\r\n      \"text\": \"我的音乐\"\r\n    }, {\r\n      \"iconPath\":\"./images/now.png\",\r\n      \"selectedIconPath\":\"./images/now1.png\",\r\n      \"pagePath\": \"pages/now/index\",\r\n      \"text\": \"正在播放\"\r\n    }, {\r\n      \"iconPath\":\"./images/account.png\",\r\n      \"selectedIconPath\":\"./images/account1.png\",\r\n      \"pagePath\": \"pages/account/index\",\r\n      \"text\": \"账号\"\r\n    }]\r\n  }\r\n}\r\n```\r\n\r\n- 发现音乐\u003cbr\u003e\r\n![](https://github.com/MengZhaoFly/wechatApp-netease_cloudmusic/blob/master/results/mysong.jpg)\u003cbr\u003e\r\n布局分为搜索框,navbar,swiper滑动，三列，以及两行三列构成\u003cbr\u003e\r\ntips:小程序中`flex`布局基本无兼容性问题 ，可大胆使用\u003cbr\u003e\r\n前三个可用上文提到的组件和小程序swiper组件快速完成，\u003cbr\u003e\r\n对于搜索功能\u003cbr\u003e\r\n我们在搜索input上绑定一个`inputTyping`事件，这样每次键入完毕都可以得到结果，然后我们直接请求api\u003cbr\u003e\r\n\r\n```js\r\n    //index.js\r\n//获取应用实例\r\n// 个人网易云音乐 ID  66919655\r\nvar app = getApp()\r\nPage({\r\n    data: {\r\n        searchReault: []\r\n    },\r\n    //绑定事件\r\n    inputTyping: function (e) {\r\n        let that = this\r\n        console.log(e.detail)\r\n        this.setData({\r\n            inputVal: e.detail.value\r\n        });\r\n        wx.request({\r\n            url: 'http://neteasemusic.leanapp.cn/search',\r\n            data: {\r\n                keywords: e.detail.value\r\n            },\r\n            method: 'GET',\r\n            success: function (res) {\r\n                let temp = []\r\n                if(!res.data.result.songs){\r\n                    return ;\r\n                }\r\n                //遍历数据\r\n                res.data.result.songs.forEach((song, index) =\u003e {\r\n                    temp.push({\r\n                        id: song.id,\r\n                        name: song.name,\r\n                        mp3Url: song.mp3Url,\r\n                        picUrl: song.album.picUrl,\r\n                        singer: song.artists[0].name\r\n                    })\r\n                    //设置数据\r\n                   that.setData({\r\n                        searchReault: temp\r\n                    })\r\n                })\r\n                // 存入搜索的结果进缓存\r\n                wx.setStorage({\r\n                    key:\"searchReault\",\r\n                    data:temp\r\n                })\r\n            }\r\n        })\r\n    }\r\n});\r\n```\r\ndata里面的searchReault数组存入搜索结果，发起一个wx.request,用GET方式传入参数，组织好json后设置data，然后将搜索结果存入本地缓存\u003cbr\u003e\r\n**wxml渲染searchReault:**\u003cbr\u003e\r\n![](https://github.com/MengZhaoFly/wechatApp-netease_cloudmusic/blob/master/results/search.jpg)\u003cbr\u003e\r\n并且自定义data属性，navigator的打开方式为tab切换`open-type=\"switchTab\"` ，绑定一个tonow事件bindtap=\"tonow\"\r\n```html\r\n\u003cblock wx:for=\"{{searchReault}}\" wx:key=\"item\" style=\"overflow-y: scroll;\"\u003e\r\n    \u003cnavigator url=\"../now/index\" class=\"weui-cell\" hover-class=\"weui-cell_active\"\r\n       data-id=\"{{item.id}}\" data-name=\"{{item.name}}\" data-songUrl=\"{{item.mp3Url}}\" data-picUrl=\"{{item.picUrl}}\" \r\n       data-singer=\"{{item.singer}}\"\r\n       open-type=\"switchTab\" bindtap=\"tonow\"\u003e\r\n       \u003cview class=\"weui-cell__bd\"\u003e\r\n          \u003cview class=\"song-name\"\u003e{{item.name}}\r\n               \u003ctext class=\"song-singer\"\u003e{{item.singer}}\u003c/text\u003e\r\n            \u003c/view\u003e\r\n         \u003c/view\u003e\r\n       \u003c/navigator\u003e\r\n\u003c/block\u003e\r\n```\r\n在tonow事件中,获取当前的歌曲\r\n```\r\n    tonow: function (event) {\r\n        let songData = {\r\n            id: event.currentTarget.dataset.id,\r\n            name: event.currentTarget.dataset.name,\r\n            mp3Url: event.currentTarget.dataset.songurl,\r\n            picUrl: event.currentTarget.dataset.picurl,\r\n            singer: event.currentTarget.dataset.singer\r\n        }\r\n        // 将当前点击的歌曲保存在缓存中\r\n        wx.setStorageSync('clickdata', songData)\r\n        wx.switchTab({\r\n            url: '../now/index'\r\n        })\r\n    }\r\n```\r\n- 正在播放\u003cbr\u003e\r\n![](https://github.com/MengZhaoFly/wechatApp-netease_cloudmusic/blob/master/results/nowplay.jpg)\u003cbr\u003e\r\n**布局：**歌曲封面，滑动条上下为操作按钮，\r\n封面在采用圆角,rotate,transition既可以\r\n**滑动快进:**在滑动条上绑定事件 slider3change\r\n```js\r\n//滑动 歌曲快进\r\nfunction sliderToseek(e, cb) {\r\n  wx.getBackgroundAudioPlayerState({\r\n    success: function (res) {\r\n      var dataUrl = res.dataUrl\r\n      var duration = res.duration\r\n      let val = e.detail.value\r\n      let cal = val * duration / 100\r\n      cb \u0026\u0026 cb(dataUrl, cal);\r\n    }\r\n  })\r\n}\r\n//分隔 在page中调用\r\n  slider3change: function (e) {\r\n    sliderToseek(e, function (dataUrl, cal) {\r\n      wx.playBackgroundAudio({\r\n        dataUrl: dataUrl\r\n      })\r\n      wx.seekBackgroundAudio({\r\n        position: cal\r\n      })\r\n    })\r\n  },\r\n```\r\n一个自定义的sliderToseek函数:\u003cbr\u003e\r\n参数e 可以获取滑动的值，获取正在播放的音乐信息成功后执行`回调函数1-\u003e播放 回调函数2-\u003e跳到指定位置`;\r\n**拆分歌词：**\r\n在api中得到的歌词：\"[00:00.00] 作曲 : 黄家驹 [00:01.00] 作词 : 黄家驹 [00:18.580]今天我 寒夜里看雪飘过 [00:25.050]怀着冷却了的心窝漂远方 [00:30.990]风雨里追赶 \"\r\n在page外定义函数：\u003cbr\u003e\r\n以`]`划分数组 第二部分就是歌词内容:`item.split(']')[1]` 第一部分即为对应的时间:`item.split(']')[0]`\r\n```js\r\n// 获取歌词\r\nfunction getlyric(id,cb) {\r\n  console.log('id:',id)\r\n  let url = `http://neteasemusic.leanapp.cn/lyric`\r\n  wx.request({\r\n    url: url,\r\n    data: {\r\n      id: id\r\n    },\r\n    method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT\r\n    // header: {}, // 设置请求的 header\r\n    success: function (res) {\r\n      // success\r\n    \r\n      if (!res.data.lrc.lyric) return false;\r\n     \r\n      let lyric = res.data.lrc.lyric\r\n     \r\n      let timearr = lyric.split('[')\r\n      let obj = {}\r\n      let lyricArr=[]\r\n      // seek 为键  歌词为value\r\n      timearr.forEach((item) =\u003e {\r\n        let key = parseInt(item.split(']')[0].split(':')[0]) * 60 + parseInt(item.split(']')[0].split(':')[1])\r\n        let val = item.split(']')[1]\r\n        \r\n        obj[key] = val\r\n      })\r\n      for(let key in obj){\r\n        // obj[key] = obj[key].split('\\n')[0]\r\n        lyricArr.push(obj[key])\r\n      }\r\n      cb\u0026\u0026cb(obj,lyricArr)\r\n    },\r\n    fail: function (res) {\r\n      // fail\r\n    },\r\n    complete: function (res) {\r\n      // complete\r\n    }\r\n  })\r\n}\r\n```\r\n在page中调用:传入歌曲ID(上文我们已经存入缓存，在缓存中取出即可),和将其设置在data的回调\r\n```js\r\n  getlyric(id,function(data, lyricArr){\r\n           that.setData({\r\n             lyricobj:data,\r\n             lyricArr:lyricArr\r\n           })\r\n         })\r\n  ```\r\n  wxml进行渲染：\r\n  ```html\r\n    \u003c!--歌词--\u003e\r\n\u003cview class=\"lyric-content\" hidden=\"{{islyric}}\" style=\"height:401px; overflow-y: scroll;\" bindtap=\"showCircle\"\u003e\r\n  \u003cview class=\"lyric\"  style=\"overflow-y: scroll;\"\u003e\r\n      \u003cblock wx:for=\"{{lyricArr}}\" \u003e\r\n\r\n        \u003cview\u003e {{item}} \u003c/view\u003e\r\n      \u003c/block\u003e\r\n    \u003c/view\u003e\r\n\r\n\u003c/view\u003e\r\n```\r\n**添加歌曲：**\u003cbr\u003e\r\n![](https://github.com/MengZhaoFly/wechatApp-netease_cloudmusic/blob/master/results/add.jpg)\r\n我的可以在本地缓存中添加两个key入对应的信息\u003cbr\u003e\r\nlike:我的喜欢\u003cbr\u003e\r\nrecent:最近\u003cbr\u003e\r\n\r\n选择事件\r\n```js\r\n  radioChange: function(e) {\r\n    console.log('radio发生change事件，携带value值为：', e.detail.value)\r\n    this.setData({\r\n      percent:'100%'\r\n    })\r\n  },\r\n  //radio发生change事件，携带value值为： like\r\n  //radio发生change事件，携带value值为： recent\r\n ```\r\n点击添加按钮，向上呼出选项，将当前播放的歌曲设置到对应的数组即可\u003cbr\u003e\r\n**进行当前歌曲的播放:**\r\n页面onshow的时候，获取本地缓存的信息，在success的回调中，设置到data,以供页面解析，而后在获取歌词的函数中也进行一次回调，设置歌词，\r\n播放本地音乐，播放成功之后，在success的回调中，获取正在播放的音乐信息，包括该歌曲的总时长，再进行设置。\r\n```\r\n  onShow: function () {\r\n    var that = this;\r\n    console.log('正在播放 is on show')\r\n    // 获取缓存\r\n    wx.getStorage({\r\n      key: 'clickdata',\r\n      success: function (res) {\r\n        var value = res.data\r\n        var id =  value.id\r\n        if (value) {\r\n          // 设置到data\r\n          that.setData({\r\n            id:id,\r\n            name: value.name,\r\n            src: value.mp3Url,\r\n            poster: value.picUrl,\r\n            author: value.singer\r\n          })\r\n         getlyric(id,function(data, lyricArr){\r\n           that.setData({\r\n             lyricobj:data,\r\n             lyricArr:lyricArr\r\n           })\r\n         }) \r\n        }\r\n        let url = that.data.src || value.mp3Url;\r\n        // 播放\r\n        wx.playBackgroundAudio({\r\n          dataUrl: value.mp3Url,\r\n          title: value.name,\r\n          coverImgUrl: value.picUrl,\r\n          success: function () {\r\n            wx.hideLoading()\r\n             console.log('url',url)\r\n             setTimeout(function(){\r\n                wx.getBackgroundAudioPlayerState({\r\n                  success: function (res) {\r\n                    var tempduration = res.duration\r\n                    console.log('get bg success', tempduration, res)\r\n                    // 设置时长\r\n                    that.setData({\r\n                      sumduration: tempduration\r\n                    })\r\n                  },\r\n                  complete: function (res) {\r\n                    console.log(' get bg complete:', res)\r\n                  }\r\n                })\r\n             },1000)\r\n          },\r\n          complete:function(){\r\n            // 获取正在播放的信息\r\n            console.log('play',url)\r\n         \r\n          }\r\n        })\r\n      }\r\n    })\r\n  },\r\n ```\r\n这样我们不知不觉进入多个回调嵌套的问题\r\n## 代码优化，使用Promise,较为优雅地解决回调\r\n**小程序暂时不支持async await**\u003cbr\u003e\r\n在 common.js 中为小程序提供的api上裹上一层Promise，并且通过`module.exports = operation`暴露出去\u003cbr\u003e\r\n```js\r\nconst operation = {\r\n    getMusicData: function () {\r\n        return new Promise((resolve, reject) =\u003e {\r\n            wx.getBackgroundAudioPlayerState({\r\n                success: function (res) {\r\n                    resolve(res);\r\n                },\r\n                fail: function (err) {\r\n                    reject(err);\r\n                }\r\n            })\r\n        })\r\n    },\r\n    // 播放音乐 参数:url title 图片url\r\n    playMusic: function (url, title, pic) {\r\n        return new Promise((resolve, reject) =\u003e {\r\n            wx.playBackgroundAudio({\r\n                dataUrl: url,\r\n                title: title,\r\n                coverImgUrl: pic,\r\n                success: function () {\r\n                    resolve(true)\r\n                },\r\n                fail: function () {\r\n                    reject(new Error('播放错误'));\r\n                }\r\n            })\r\n        })\r\n    },\r\n    asyncGetStorage: function (key) {\r\n        return new Promise((resolve, reject) =\u003e {\r\n            wx.getStorage({\r\n                key: key,\r\n                success: function (res) {\r\n                    resolve(res.data)\r\n                },\r\n                fail: function (err) {\r\n                    reject(err)\r\n                }\r\n            })\r\n        })\r\n    },\r\n    getlyric: function (id) {\r\n        return new Promise((resolve, reject) =\u003e {\r\n            console.log('id:', id)\r\n            let url = `http://neteasemusic.leanapp.cn/lyric`\r\n            wx.request({\r\n                url: url,\r\n                data: {\r\n                    id: id\r\n                },\r\n                method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT\r\n                // header: {}, // 设置请求的 header\r\n                success: function (res) {\r\n                    // success\r\n                    if (!res.data.lrc.lyric) return false;\r\n                    let lyric = res.data.lrc.lyric\r\n                    let timearr = lyric.split('[')\r\n                    let obj = {}\r\n                    let lyricArr = []\r\n                    // seek 为键  歌词为value\r\n                    timearr.forEach((item) =\u003e {\r\n                        let key = parseInt(item.split(']')[0].split(':')[0]) * 60 + parseInt(item.split(']')[0].split(':')[1])\r\n                        let val = item.split(']')[1]\r\n                        obj[key] = val\r\n                    })\r\n                    for (let key in obj) {\r\n                        // obj[key] = obj[key].split('\\n')[0]\r\n                        lyricArr.push(obj[key])\r\n                    }\r\n                    // cb \u0026\u0026 cb(obj, lyricArr)\r\n                    resolve(lyricArr)\r\n                },\r\n                fail: function (err) {\r\n                    reject(err)\r\n                },\r\n                complete: function (res) {\r\n                    // complete\r\n                }\r\n            })\r\n        })\r\n    }\r\n}\r\nmodule.exports = operation\r\n```\r\n重写一下**当前歌曲播放事件**\r\n```js\r\n  onShow: function () {\r\n    let that = this;\r\n    Common.asyncGetStorage('clickdata')//本地缓存\r\n      .then(data =\u003e {\r\n        // console.log(data)\r\n        if (!data) return;\r\n        that.setData({\r\n          id: data.id,\r\n          name: data.name,\r\n          src: data.mp3Url,\r\n          poster: data.picUrl,\r\n          author: data.singer\r\n        })\r\n        return Common.playMusic(data.mp3Url,  data.name, data.picUrl);\r\n      })\r\n      .then(status =\u003e {\r\n        if(!status) return;\r\n        wx.hideLoading();\r\n        console.log('id,',that.data.id)\r\n        return Common.getlyric(that.data.id)\r\n      })\r\n      .then((lyricArr) =\u003e {\r\n        console.log('lyricArr',lyricArr)\r\n        that.setData({\r\n          lyricArr: lyricArr\r\n        })\r\n        return Common.getMusicData()\r\n      })\r\n      .then(data =\u003e {\r\n        let tempduration = data.duration\r\n        console.log('get bg success', tempduration, data)\r\n        // 设置时长\r\n        that.setData({\r\n          sumduration: tempduration\r\n        })\r\n      })\r\n  },\r\n  ```\r\n  这样即可缩减部分代码.\r\n***\r\n## 有帮助可以Star\r\n18届小前端求职中`['html/html5', 'css/css3', 'js/es5/es6', 'node']`\r\n\u003ca href=\"mailto:1424254461@qq.com\"\u003e1424254461@qq.com\u003c/a\u003e\r\n\r\n\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMengZhaoFly%2FwechatApp-netease_cloudmusic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMengZhaoFly%2FwechatApp-netease_cloudmusic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMengZhaoFly%2FwechatApp-netease_cloudmusic/lists"}