todo:

添加音乐到收藏(最近)列表

歌词滚动

从一个 hello world 开始


微信开发者工具生成 目录如下:

.
|-- app.js
|-- app.json
|-- app.wxss
|-- pages
|   |-- index   # 主页
|   |   |-- index.js
|   |   |-- index.json
|   |   |-- index.wxml
|   |   `-- index.wxss
|   `-- log # 日志页面
|   |   |-- log.js
|   |   |-- log.json
|   |   |-- log.wxml
|   |   `-- log.wxss
`-- utils       # 工具`-- util.js

大体为: 每一个 page 即是一个页面文件 ,每个页面有一个 js/wxml/wxss/json 文件 规定:描述页面的这四个文件必须具有相同的路径与文件名。

全局下同路,为公共的逻辑,样式,配置

与 HTML 不同:用 view text navigator 代替 div span a

开发者文档走马观花


app.json: 注册 pages window tabBar networkTimeout

组件说明

.js: 作为逻辑层 与 wxml 交互 有着丰富的 网络, 媒体, 文件, 数据缓存, 位置, 设备, 界面...的 API

官方文档

.wxml: 数据驱动的视图层 + 微信提供了大量的组件 表单 导航 媒体 ...

官方组件不够,weui 来凑


weui 为小程序提供了 weui.wxcss 但大多是造官方组件的轮子

这里精选,也算是补充两个常用组件

对于小程序没有 DOM 操作 不熟悉 mvvm 思想的同学 是个很好的入门

navbar

<!-- wxml --><viewclass="weui-tab"><viewclass="weui-navbar"><blockwx:for="{{tabs}}"wx:key="*this"><viewid="{{index}}"class="weui-navbar__item {{activeIndex == index ? 'weui-bar__item_on' : ''}}"bindtap="tabClick"><viewclass="weui-navbar__title">{{item}}</view></view></block><viewclass="weui-navbar__slider"style="left: {{sliderLeft}}px; transform: translateX({{sliderOffset}}px); -webkit-transform: translateX({{sliderOffset}}px);"></view></view><viewclass="weui-tab__panel"><viewclass="weui-tab__content"hidden="{{activeIndex != 0}}">选项一的内容</view><viewclass="weui-tab__content"hidden="{{activeIndex != 1}}">选项二的内容</view><viewclass="weui-tab__content"hidden="{{activeIndex != 2}}">选项三的内容</view></view></view>

block 渲染 data 里面的四个 tabs,slider 为激活 tab 选项时候的表现,panel 为内容面板

//js
varsliderWidth=96;// 需要设置slider的宽度,用于计算中间位置
Page({data:{tabs:["选项一","选项二","选项三"],activeIndex:1,sliderOffset:0,sliderLeft:0},onLoad:function(){varthat=this;wx.getSystemInfo({success:function(res){that.setData({sliderLeft:(res.windowWidth/that.data.tabs.length-sliderWidth)/2,sliderOffset:res.windowWidth/that.data.tabs.length*that.data.activeIndex});}});},tabClick:function(e){this.setData({sliderOffset:e.currentTarget.offsetLeft,activeIndex:e.currentTarget.id});}});

了解 mvvm 思想的同学不难看出 通过 tabs 数组渲染出来选项后每次点击获取 id 然后通过设置 hidden 显示或隐藏

searchbar

<viewclass="weui-search-bar"><viewclass="weui-search-bar__form"><viewclass="weui-search-bar__box"><iconclass="weui-icon-search_in-box"type="search"size="14"></icon><inputtype="text"class="weui-search-bar__input"placeholder="搜索"value="{{inputVal}}"focus="{{inputShowed}}"bindinput="inputTyping"/><viewclass="weui-icon-clear"wx:if="{{inputVal.length > 0}}"bindtap="clearInput"><icontype="clear"size="14"></icon></view></view><labelclass="weui-search-bar__label"hidden="{{inputShowed}}"bindtap="showInput"><iconclass="weui-icon-search"type="search"size="14"></icon><viewclass="weui-search-bar__text">搜索</view></label></view><viewclass="weui-search-bar__cancel-btn"hidden="{{!inputShowed}}"bindtap="hideInput">取消</view></view><viewclass="weui-cells searchbar-result"wx:if="{{inputVal.length > 0}}"><navigatorurl=""class="weui-cell"hover-class="weui-cell_active"><viewclass="weui-cell__bd"><view>实时搜索文本</view></view></navigator></view>

一个 input 输入框 + 一个搜索 label+ 一个清楚内容的 icon + 取消按钮

Page({data:{inputShowed:false,inputVal:""},showInput:function(){this.setData({inputShowed:true});},hideInput:function(){this.setData({inputVal:"",inputShowed:false});},clearInput:function(){this.setData({inputVal:""});},inputTyping:function(e){this.setData({inputVal:e.detail.value});}});

input 上面有一层 label 通过 Page 里面状态的改变而操作其 wxml 状态的改变

不难体会到:小程序和 Vue 的思想还是挺接近的

站在巨人的肩膀上为大佬们提供云音乐 API


---获取云音乐api

巨人的源 github 项目

在此我将他部署到 leancloud 上

即可在线访问,免去烦人的本地 localhost 启动,在线 url

http://neteasemusic.leanapp.cn

调用例子:

http://neteasemusic.leanapp.cn/search?keywords=海阔天空

http://neteasemusic.leanapp.cn/lyric?id=347230

具体参考 API

详细文档

一切具备 只欠东风


生成目录

.
|-- app.js
|-- app.json
|-- app.wxss
|-- common.js #公用js
|-- images #存放项目图片
|-- style
|  |-- weui.wxss  # 引入weui样式 万一你自己不想写css样式呢
|-- pages
|  |-- find  # 发现音乐
|  |  |-- index.js
|   |   |-- index.json
|   |   |-- index.wxml
|   |   `-- index.wxss
|  |--my  # 我的音乐
|  |  |-- index.js
|   |   |-- index.json
|   |   |-- index.wxml
|   |   `-- index.wxss
|  |--now # 正在播放
|  |  |-- index.js
|   |   |-- index.json
|   |   |-- index.wxml
|   |   `-- index.wxss
|  |--account  # 账号
|  |  |-- index.js
|   |   |-- index.json
|   |   |-- index.wxml
|   |   `-- index.wxss
|   |-- index   # 主页
|   |   |-- index.js
|   |   |-- index.json
|   |   |-- index.wxml
|   |   `-- index.wxss
|   `-- log # 日志页面
`-- utils       # 工具`-- util.js

请先在在 app.json 中注册页面,设置 navigation,配置 tabbar

{"pages":["pages/find/index","pages/my/index","pages/now/index","pages/account/index","pages/index/index"],"window":{"backgroundTextStyle":"light","navigationBarBackgroundColor":"#D43C33","navigationBarTitleText":"网易云音乐","navigationBarTextStyle":"white","backgroundColor":"#FBFCFD"},"tabBar":{"backgroundColor":"#2A2C2E","color":"#a7a7a7","selectedColor":"#ffffff","list":[{"iconPath":"./images/find.png","selectedIconPath":"./images/find1.png","pagePath":"pages/find/index","text":"发现音乐"},{"iconPath":"./images/my.png","selectedIconPath":"./images/my1.png","pagePath":"pages/my/index","text":"我的音乐"},{"iconPath":"./images/now.png","selectedIconPath":"./images/now1.png","pagePath":"pages/now/index","text":"正在播放"},{"iconPath":"./images/account.png","selectedIconPath":"./images/account1.png","pagePath":"pages/account/index","text":"账号"}]}}

发现音乐

布局分为搜索框,navbar,swiper 滑动,三列,以及两行三列构成

tips:小程序中 flex 布局基本无兼容性问题 ,可大胆使用

前三个可用上文提到的组件和小程序 swiper 组件快速完成,

对于搜索功能

我们在搜索 input 上绑定一个 inputTyping 事件,这样每次键入完毕都可以得到结果,然后我们直接请求 API

//index.js
//获取应用实例
// 个人网易云音乐 ID  66919655
varapp=getApp()Page({data:{searchReault:[]},//绑定事件
inputTyping:function(e){letthat=thisconsole.log(e.detail)this.setData({inputVal:e.detail.value});wx.request({url:'http://neteasemusic.leanapp.cn/search',data:{keywords:e.detail.value},method:'GET',success:function(res){lettemp=[]if(!res.data.result.songs){return;}//遍历数据
res.data.result.songs.forEach((song,index)=>{temp.push({id:song.id,name:song.name,mp3Url:song.mp3Url,picUrl:song.album.picUrl,singer:song.artists[0].name})//设置数据
that.setData({searchReault:temp})})// 存入搜索的结果进缓存
wx.setStorage({key:"searchReault",data:temp})}})}});

data 里面的 searchReault 数组存入搜索结果,发起一个 wx.request,用 GET 方式传入参数,组织好 JSON 后设置 data,然后将搜索结果存入本地缓存

wxml 渲染 searchReault:

并且自定义 data 属性,navigator 的打开方式为 tab 切换 open-type="switchTab" ,绑定一个 tonow 事件 bindtap="tonow"

<blockwx:for="{{searchReault}}"wx:key="item"style="overflow-y: scroll;"><navigatorurl="../now/index"class="weui-cell"hover-class="weui-cell_active"data-id="{{item.id}}"data-name="{{item.name}}"data-songUrl="{{item.mp3Url}}"data-picUrl="{{item.picUrl}}"data-singer="{{item.singer}}"open-type="switchTab"bindtap="tonow"><viewclass="weui-cell__bd"><viewclass="song-name">{{item.name}}<textclass="song-singer">{{item.singer}}</text></view></view></navigator></block>

在 tonow 事件中,获取当前的歌曲

    tonow: function (event) {let songData = {id: event.currentTarget.dataset.id,name: event.currentTarget.dataset.name,mp3Url: event.currentTarget.dataset.songurl,picUrl: event.currentTarget.dataset.picurl,singer: event.currentTarget.dataset.singer}// 将当前点击的歌曲保存在缓存中wx.setStorageSync('clickdata', songData)wx.switchTab({url: '../now/index'})}

正在播放

布局:歌曲封面,滑动条上下为操作按钮, 封面在采用圆角,rotate,transition 既可以 滑动快进:在滑动条上绑定事件 slider3change

//滑动 歌曲快进
functionsliderToseek(e,cb){wx.getBackgroundAudioPlayerState({success:function(res){vardataUrl=res.dataUrlvarduration=res.durationletval=e.detail.valueletcal=val*duration/100cb&&cb(dataUrl,cal);}})}//分隔 在page中调用
slider3change:function(e){sliderToseek(e,function(dataUrl,cal){wx.playBackgroundAudio({dataUrl:dataUrl})wx.seekBackgroundAudio({position:cal})})},

一个自定义的 sliderToseek 函数:

参数 e 可以获取滑动的值,获取正在播放的音乐信息成功后执行 回调函数1->播放 回调函数2->跳到指定位置; 拆分歌词: 在 API 中得到的歌词:"[00:00.00] 作曲 : 黄家驹 [00:01.00] 作词 : 黄家驹 [00:18.580]今天我 寒夜里看雪飘过 [00:25.050]怀着冷却了的心窝漂远方 [00:30.990]风雨里追赶 " 在 page 外定义函数:

以 ] 划分数组 第二部分就是歌词内容:item.split(']')[1] 第一部分即为对应的时间:item.split(']')[0]

// 获取歌词
functiongetlyric(id,cb){console.log('id:',id)leturl=`http://neteasemusic.leanapp.cn/lyric`wx.request({url:url,data:{id:id},method:'GET',// OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
// header: {}, // 设置请求的 header
success:function(res){// success
if(!res.data.lrc.lyric)returnfalse;letlyric=res.data.lrc.lyriclettimearr=lyric.split('[')letobj={}letlyricArr=[]// seek 为键  歌词为value
timearr.forEach((item)=>{letkey=parseInt(item.split(']')[0].split(':')[0])*60+parseInt(item.split(']')[0].split(':')[1])letval=item.split(']')[1]obj[key]=val})for(letkeyinobj){// obj[key] = obj[key].split('\n')[0]
lyricArr.push(obj[key])}cb&&cb(obj,lyricArr)},fail:function(res){// fail
},complete:function(res){// complete
}})}

在 page 中调用:传入歌曲 ID(上文我们已经存入缓存,在缓存中取出即可),和将其设置在 data 的回调

getlyric(id,function(data,lyricArr){that.setData({lyricobj:data,lyricArr:lyricArr})})

wxml 进行渲染:

<!--歌词--><viewclass="lyric-content"hidden="{{islyric}}"style="height:401px; overflow-y: scroll;"bindtap="showCircle"><viewclass="lyric"style="overflow-y: scroll;"><blockwx:for="{{lyricArr}}"><view> {{item}} </view></block></view></view>

添加歌曲:

我的可以在本地缓存中添加两个 key 入对应的信息

like:我的喜欢

recent:最近

选择事件

radioChange:function(e){console.log('radio发生change事件,携带value值为:',e.detail.value)this.setData({percent:'100%'})},//radio发生change事件,携带value值为: like
//radio发生change事件,携带value值为: recent

点击添加按钮,向上呼出选项,将当前播放的歌曲设置到对应的数组即可

进行当前歌曲的播放: 页面 onshow 的时候,获取本地缓存的信息,在 success 的回调中,设置到 data,以供页面解析,而后在获取歌词的函数中也进行一次回调,设置歌词, 播放本地音乐,播放成功之后,在 success 的回调中,获取正在播放的音乐信息,包括该歌曲的总时长,再进行设置。

  onShow: function () {var that = this;console.log('正在播放 is on show')// 获取缓存wx.getStorage({key: 'clickdata',success: function (res) {var value = res.datavar id =  value.idif (value) {// 设置到datathat.setData({id:id,name: value.name,src: value.mp3Url,poster: value.picUrl,author: value.singer})getlyric(id,function(data, lyricArr){that.setData({lyricobj:data,lyricArr:lyricArr})}) }let url = that.data.src || value.mp3Url;// 播放wx.playBackgroundAudio({dataUrl: value.mp3Url,title: value.name,coverImgUrl: value.picUrl,success: function () {wx.hideLoading()console.log('url',url)setTimeout(function(){wx.getBackgroundAudioPlayerState({success: function (res) {var tempduration = res.durationconsole.log('get bg success', tempduration, res)// 设置时长that.setData({sumduration: tempduration})},complete: function (res) {console.log(' get bg complete:', res)}})},1000)},complete:function(){// 获取正在播放的信息console.log('play',url)}})}})},

这样我们不知不觉进入多个回调嵌套的问题

代码优化,使用 Promise,较为优雅地解决回调


小程序暂时不支持 async await

在 common.js 中为小程序提供的 API 上裹上一层 Promise,并且通过 module.exports = operation 暴露出去

const operation = {getMusicData: function () {return new Promise((resolve, reject) => {wx.getBackgroundAudioPlayerState({success: function (res) {resolve(res);},fail: function (err) {reject(err);}})})},// 播放音乐 参数:url title 图片urlplayMusic: function (url, title, pic) {return new Promise((resolve, reject) => {wx.playBackgroundAudio({dataUrl: url,title: title,coverImgUrl: pic,success: function () {resolve(true)},fail: function () {reject(new Error('播放错误'));}})})},asyncGetStorage: function (key) {return new Promise((resolve, reject) => {wx.getStorage({key: key,success: function (res) {resolve(res.data)},fail: function (err) {reject(err)}})})},getlyric: function (id) {return new Promise((resolve, reject) => {console.log('id:', id)let url = `http://neteasemusic.leanapp.cn/lyric`wx.request({url: url,data: {id: id},method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT// header: {}, // 设置请求的 headersuccess: function (res) {// successif (!res.data.lrc.lyric) return false;let lyric = res.data.lrc.lyriclet timearr = lyric.split('[')let obj = {}let lyricArr = []// seek 为键  歌词为valuetimearr.forEach((item) => {let key = parseInt(item.split(']')[0].split(':')[0]) * 60 + parseInt(item.split(']')[0].split(':')[1])let val = item.split(']')[1]obj[key] = val})for (let key in obj) {// obj[key] = obj[key].split('\n')[0]lyricArr.push(obj[key])}// cb && cb(obj, lyricArr)resolve(lyricArr)},fail: function (err) {reject(err)},complete: function (res) {// complete}})})}
}
module.exports = operation

重写一下当前歌曲播放事件

onShow: function () {let that = this;Common.asyncGetStorage('clickdata')//本地缓存.then(data => {// console.log(data)if (!data) return;that.setData({id: data.id,name: data.name,src: data.mp3Url,poster: data.picUrl,author: data.singer})return Common.playMusic(data.mp3Url,  data.name, data.picUrl);}).then(status => {if(!status) return;wx.hideLoading();console.log('id,',that.data.id)return Common.getlyric(that.data.id)}).then((lyricArr) => {console.log('lyricArr',lyricArr)that.setData({lyricArr: lyricArr})return Common.getMusicData()}).then(data => {let tempduration = data.durationconsole.log('get bg success', tempduration, data)// 设置时长that.setData({sumduration: tempduration})})},

这样即可缩减部分代码.

完整代码:https://download.csdn.net/download/weixin_55771290/87402443

网易云音乐小程序案例分享 附完整代码相关推荐

  1. 网易云音乐小程序,带后台(SpringBoot)

    目录 1.简介 2.技术栈 3.环境 4.项目后台配置 5.项目展示 6.下载地址 1.简介 此系统是仿网易云音乐 网易云音乐是一款专注于发现与分享的音乐产品,依托专业音乐人.DJ.好友推荐及社交功能 ...

  2. taro 重新加载小程序_taro-music一款开源网易云音乐小程序

    简介 taro-music 是基于taro + taro-ui + redux + react-hooks + typescript 开发的网易云音乐小程序,目前正在使用react-hooks重构中. ...

  3. 简单的仿网易云音乐小程序(总结)

    简单的仿网易云音乐小程序(总结) 这个小程序学到了以下知识点 配置网络请求 进行网络请求 进行音乐播放 进行模版使用 各种页面触发事件 输入框的使用 简单的自定义tab页面切换 导航的数据传输

  4. 简单的仿网易云音乐小程序(一)

    简单的仿网易云音乐小程序(一) 前言 思维图 注意事项 虚拟机调试 真机调试 主页面 搜索框 歌单列表 歌单模版 wxs filter 页面逻辑 等待搜索页面 搜索框 clearValue start ...

  5. 如何用 Python 爬取网易云音乐的 10w+ 评论?附详细代码解读

    在简单学习了Python爬虫之后,我的下一个目标就是网易云音乐.因为本人平时就是用它听的歌,也喜欢看歌里的评论,所以本文就来爬一爬网易云音乐的评论吧! 正式进入主题 首先是找到目标网页并分析网页结构, ...

  6. 网易云音乐小程序登录接口显示400,拥挤问题解决

    有在做网易云登录接口的小伙伴会发现自己会出现如下问题 解决办法: 用这个接口:https://neteasecloudmusicapi.js.org/#/ 配置好,先cmd,再npm i,如果出现np ...

  7. 网易云音乐小程序 笔记

    小程序750px html 双引号 js 单引号 flex布局:弹性盒子 授权动作只发生一次 获取用户信息 flex-direction: column; // 修改flex主轴x修改为y lign- ...

  8. 网易云音乐排行榜接口取消后解决方法(网易云音乐小程序)

    解决办法: 结合"所有榜单"和"获取歌单详情"两个api获取.因为获取歌单详情api只能获取单个歌单的内容,所以要先获得多个歌单id. 完整代码: let to ...

  9. netease-im网易云通信小程序集成实践+群组功能完善

    在微信里放一个IM,被指定放网易云通信.这次实践是一场非常虐心的体验,虽然集成网易云通信有官方资料参考,也有官方的demo参考,但是踩的坑也不少. 一.不完全是技术问题 消息漫游需要联系商务开通 二. ...

最新文章

  1. apktoolkit apk反编译没有文件_重新编译mono——修改apk中Assembly-CSharp.dll并重新打包...
  2. 从中心走向边缘——深度解析云原生边缘计算落地痛点
  3. rest-framework之响应器(渲染器)
  4. ElasticSearch入门 —— 集群搭建
  5. 银行家算法实验报告c语言版,银行家算法实验报告C语言版.doc
  6. python---基础知识
  7. Android Lint简介
  8. 万用表二极管档和三极管档的使用
  9. 自己怎么开发一个软件app、如何开发一个app系统软件?
  10. c语言求圆锥的表面积和体积_c语言如何编程求圆体积和表面积
  11. 五大方面多管齐下,用友助力企业建设世界一流司库体系
  12. github国内镜像
  13. 解决Nginx出现 403 Forbidden的办法
  14. 圖譜謎宮(2019年6月28日於鄂爾多斯)
  15. C语言入门part4—大致梳理最终篇
  16. 【快乐手撕LeetCode题解系列】——消失的数字
  17. html+css+js制作美团界面
  18. 弹出式网络广告价值分析案例
  19. java jdk8 使用stream实现两个list集合合并成一个list集合(对象属性的合并)
  20. 计算机网络(第八版 谢希仁著)(上)

热门文章

  1. 12月21诛仙服务器维护,诛仙手游正式服12月22日例行更新维护公告
  2. go-cqhttp发送本地图片
  3. 3600000毫秒等于多少小时_工地扬尘监测规定-多少算超标?
  4. 万卷书- 创新型学校 [Creative Schools]
  5. UML建模工具Astah Pro教程
  6. 计算机图像技术在医学上的应用,计算机图像处理技术在医学中的应用
  7. 区块链技术加持下的十款智能硬件产(kuang)品(ji)
  8. 电子邮箱格式怎么写?你知道电子邮箱格式都有哪些吗?
  9. Flash中使用Filereference上传文件的一些注意事项
  10. Newtonsoft.Json取json字符串中的值得用法 这里是取的时候