仿网易云音乐-微信小程序开发
1.很多时候要找到完整的API接口很难,但网易云音乐的数据API是可以得到完整的。
安装API:https://github.com/Binaryify/NeteaseCloudMusicApi,只需按照步骤部署就可以的。
提示:由于本地电脑环境千差万别,建议会使用virtualBox虚拟机进行部署可一劳永逸
部署完成, cd NeteaseCloudMusicApi node app.js 开启服务即可
2.根据相关API开发页面
获取推荐歌单列表
tabBar,主页面色,以及路由设计
{
"pages": [
"pages/home/home",
"pages/hot/hot",
"pages/search/search",
"pages/listdetail/listdetail",
"pages/musicplay/musicplay" ],
"window": {
"backgroundColor": "#F6F6F6",
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#d43c33",
"navigationBarTitleText": "网易云音乐",
"navigationBarTextStyle": "white"
},
"tabBar": {
"backgroundColor": "#212121",
"color": "#8F8F8F",
"selectedColor": "#FFF",
"list": [{
"pagePath": "pages/home/home",
"text": "推荐音乐",
"iconPath": "/images/cm2_btm_icn_discovery.png",
"selectedIconPath": "/images/cm2_btm_icn_discovery_prs.png" },
{
"pagePath": "pages/hot/hot",
"text": "热歌榜",
"iconPath": "/images/cm2_btm_icn_radio.png",
"selectedIconPath": "/images/cm2_btm_icn_radio_prs.png"
},
{
"pagePath": "pages/search/search",
"text": "搜索",
"iconPath": "/images/cm2_btm_icn_music.png",
"selectedIconPath": "/images/cm2_btm_icn_music_prs.png"
}
]
},
"requiredBackgroundModes": ["audio", "location"],
"sitemapLocation": "sitemap.json"
}
tabBar,主页面色,以及路由设计
若需要在小程序切后台后继续播放音频,需要在 app.json 中配置 requiredBackgroundModes
属性。
获取API数据,此时有两种方法,使用小程序云函数,或者本地获取
本地获取:
封装request请求get,post
const baseurl = 'http://localhost:3000'
function getbaseurl() {
return baseurl;
}
//get请求
function get(url, data) {
return new Promise((reslove, reject) => {
wx.request({
method: 'GET',
url: baseurl + url,
data,
success: reslove,
fail: reject
})
})
} //post请求
function post(url, data) {
return new Promise((reslove, reject) => {
wx.request({
method: 'POST',
url: baseurl + url,
data,
success: reslove,
fail: reject
})
})
} //需要导出
module.exports = {
get,
post,
getbaseurl
}
request.js
// pages/home/home.js
var requestUrl = require('../../utils/request.js')
Page({ /**
* 页面的初始数据
*/
data: {
musicList: [ ],
detailUrl:''
}, /**
* 生命周期函数--监听页面加载
*/
onLoad: async function (options) {
const res = await requestUrl.get('/personalized/?limit=6')
this.setData({ musicList: res.data.result});
console.log(res.data.result)
},
获取歌单列表
自定义组件还可以自己触发双向绑定更新,做法就是:使用 setData 设置自身的属性
<wxs module="common" src="../../utils/utils.wxs"></wxs>
<view class="m-homeremd">
<h2 class="remd_tl"> 推荐歌单</h2>
<view class="remd_ul">
<navigator url="../listdetail/listdetail?id={{item.id}}" class="remd_li" data-musicid="{{item.id}}" wx:for="{{musicList}}" wx:key="index">
<view class="remd_img">
<image class="u-img" src="{{item.picUrl}}"></image>
<span class="u-earp remd_lnum">{{common.numberFormat(item.playCount)}}</span>
</view>
<text class="remd_text">{{item.name}}</text>
</navigator>
</view>
</view>
渲染歌单页面
推荐歌单页面有一个播放量转换
function numberFormat(value) {
var param = {};
var k = 10000,
sizes = ['', '万', '亿', '万亿'],
i;
if (value < k) {
param.value = value
param.unit = ''
} else {
i = Math.floor(Math.log(value) / Math.log(k)); param.value = ((value / Math.pow(k, i))).toFixed(2);
param.unit = sizes[i];
}
return param.value + param.unit;
}
module.exports = {
numberFormat: numberFormat
}
utils.wxs
.m-homeremd {
padding-top: 20px;
}
.m-homeremd .remd_tl {
position: relative;
padding-left: 9px;
margin-bottom: 14px;
font-size: 17px;
height: 20px;
line-height: 20px;
}
.m-homeremd .remd_tl:after {
content: " ";
position: absolute;
left: 0;
top: 50%;
margin-top: -9px;
width: 2px;
height: 16px;
background-color: #d33a31;
} .m-homeremd .remd_ul{
display: flex;
flex-wrap: wrap;
}
.m-homeremd .remd_li{
box-sizing: border-box;
flex: 0 1 33.3%;
padding-bottom: 20px;
}
.m-homeremd .remd_img>.u-img{
width: 100px;
height: 100px;
}
.m-homeremd .remd_text {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
padding: 6px 2px 0 6px;
min-height: 30px;
line-height: 1.2;
font-size: 13px;
}
.m-homeremd .remd_img {
position: relative;
}
.m-homeremd .remd_lnum {
position: absolute;
right: 5px;
top: 2px;
z-index: 3;
padding-left: 13px;
color: #fff;
font-size: 12px;
background-position: 0;
background-repeat: no-repeat;
background-size: 11px 10px;
text-shadow: 1px 0 0 rgba(0,0,0,.15);
}
.u-earp {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAQAAABKfvVzAAABfUlEQVR4AZXSA0y/YRAH8PvbdhqyrbnmMDPXFIYwZmt2bo5jDRlDtu1mZHc9z737/Z7t4n833ffu8+p5Af+zePAZQ7AaB3AF57Ebq0X35X7wBhNxEXdZLWKSmNwB/mATW1XVjH84+IdD2nC/tyclLuC9u5l3QmBXyn6vlorpPwXkw7TK+HqjJ+WVG7iqeuXWlXK9QaQV3ygQQ+ubFVFiyRp+gRjBc3gLP0XnWh11vUkkRgc+45wMetPBBX7xzyiQS28agTmxSSBYtof9X9zg051f/vMXt8N+IqEErqpl05/Dr64KfvVnyx2xKcHFsGyKA+DZveBZob/cuRgigNui2YE/D/4Qf2hrm4D2peHdg+CdtoUKoC+OifLhq/pcgWt6JBylYIADfa4eabH0amW5jGJRHOjypfKrlaUyAuAif4LHgParaMAYnMHkMUBbxgh8wAHPFTin/+l0ggOWK9AYdzZzPl8bwwDPFQBHei17DlTOwVdwEMMvHPAc8D/rBs0Gmx5Y/w/0AAAAAElFTkSuQmCC');
}
css样式
列表页面渲染:根据id值跳转到相对应的列表页面
import {get} from "../../utils/request.js"
// pages/listdetail/listdetail.js
Page({ /**
* 页面的初始数据
*/
data: {
detailList:[ ]
}, /**
* 生命周期函数--监听页面加载
*/
onLoad: async function (options) {
console.log(options)
const url =`/playlist/detail?id=${options.id}`
const res = await get(url)
console.log(res.data)
this.setData({ detailList: res.data.playlist}) },
listdetail.js
<!-- <wxs module="common" src="../../utils/utils.wxs"></wxs>
<view class="u-plhead pylst_header">
<view class="plhead_bg" style="background-image:url({{detailList.playlist.coverImgUrl}})">
</view>
<view class="plhead_wrap">
<view class="plhead_fl lsthd_fl">
<image src="{{detailList.playlist.coverImgUrl}}" class='u-img'>{{detailList.playlist.coverImgUrl}}</image>
<span class="lsthd_icon">歌单</span>
<i class="u-earp lsthd_num">{{common.numberFormat(detailList.playlist.playCount)}}</i>
</view>
<view class="plhead_fr">
<h2 class="f-thide2 f-brk lsthd_title">{{detailList.playlist.name}}</h2>
<view class="lsthd_auth f-thide">
<a class="lsthd_link" href="">
<view class="u-avatar lsthd_ava">
<image class="u-img" src="{{detailList.playlist.creator.avatarUrl}}"></image>
<span class="ava-icon ava-icon-daren"></span> </view>
{{detailList.playlist.creator.nickname}}
</a>
</view>
</view>
</view>
</view>
<h3 class="u-smtitle">歌曲列表</h3>
<view class="m-sglst"wx:for="{{detailList}}" wx:key="index">
<view class="m-list"wx:for="{{item.tracks}}" wx:for-item="item" wx:key="index">
<navigator class="m-sgitem"url="/">
<view class="sgfl">{{index+1}}</view>
<view class="sgfr f-bd f-bd-btm">
<view class="sgchfl">
<view class="f-thide sgtl">{{item.name}}</view>
<view class="f-thide sginfo">{{}}</view>
</view>
<view class="sgchfr">
<span class="u-hmsprt sgchply">
</span>
</view>
</view>
</navigator>
</view>
</view> -->
<wxs module="common" src="../../utils/utils.wxs"></wxs>
<view class="u-plhead pylst_header">
<view class="plhead_bg" style="background-image:url({{detailList.coverImgUrl}})">
</view>
<view class="plhead_wrap">
<view class="plhead_fl lsthd_fl">
<image w-if="detailList.coverImgUrl" src="{{detailList.coverImgUrl}}" class='u-img'></image>
<span class="lsthd_icon">歌单</span>
<i class="u-earp lsthd_num">{{common.numberFormat(detailList.playCount)}}</i>
</view>
<view class="plhead_fr">
<h2 class="f-thide2 f-brk lsthd_title">{{detailList.name}}</h2>
<view class="lsthd_auth f-thide">
<a class="lsthd_link" href="">
<view class="u-avatar lsthd_ava">
<image class="u-img" src="{{detailList.creator.avatarUrl}}"></image>
<span class="ava-icon ava-icon-daren"></span> </view>
{{detailList.creator.nickname}}
</a>
</view>
</view>
</view>
</view>
<h3 class="u-smtitle">歌曲列表</h3>
<view class="m-sglst"wx:for="{{detailList.tracks}}" wx:key="index">
<!-- <view class="m-list"wx:for="{{item.tracks}}" wx:for-item="item" wx:key="index"> -->
<navigator class="m-sgitem"url="../musicplay/musicplay?id={{item.id}}&title={{item.name}}">
<view class="sgfl">{{index+1}}</view>
<view class="sgfr f-bd f-bd-btm">
<view class="sgchfl">
<view class="f-thide sgtl">{{item.name}}
<span class="sgalia" wx:if="{{item.alia.length}}">(<!-- -->{{item.alia}}<!-- -->)</span>
</view>
<view class="f-thide sginfo">{{item.ar[0].name}}-{{item.al.name}}</view>
</view>
<view class="sgchfr">
<span class="u-hmsprt sgchply">
</span>
</view>
</view>
</navigator>
<!-- </view> -->
</view>
listdetail页面渲染
.plhead_wrap {
display: flex;
position: relative;
z-index: 2;
}
.u-plhead {
position: relative;
padding: 30px 10px 30px 15px;
overflow: hidden;
}
.u-plhead .plhead_bg {
background-repeat: no-repeat;
background-size: cover;
background-position: 50%;
-webkit-filter: blur(20px);
filter: blur(20px);
-webkit-transform: scale(1.5);
-ms-transform: scale(1.5);
transform: scale(1.5);
}
.u-plhead .plhead_bg, .u-plhead .plhead_bg:after {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 1;
}
.u-plhead .plhead_bg:after {
content: " ";
background-color: rgba(0,0,0,.25);
}
.pylst_header .lsthd_title {
padding-top: 1px;
font-size: 17px;
line-height: 1.3;
color: #fefefe;
height: 44px;
display: -webkit-box;
-webkit-box-pack: center;
}
.plhead_fl {
position: relative;
width: 114px;
height: 114px;
background-color: #e2e2e3;
}
image.u-img {
width: 100%;
height: 100%;
}
.pylst_header .lsthd_icon {
position: absolute;
z-index: 3;
top: 10px;
left: 0;
padding: 0 8px;
height: 17px;
color: #fff;
font-size: 9px;
text-align: center;
line-height: 17px;
background-color: rgba(217,48,48,.8);
border-top-right-radius: 17px;
border-bottom-right-radius: 17px;
}
.u-plhead .plhead_fr {
-webkit-box-flex: 1;
-webkit-flex: 1 1 auto;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
width: 1%;
margin-left: 16px;
}
.pylst_header .lsthd_ava {
display: inline-block;
width: 30px;
height: 30px;
border-radius: 50%;
vertical-align: middle;
margin-right: 5px;
}
.u-avatar {
position: relative;}
.u-avatar>.u-img {
border-radius: 50%; }
.u-avatar .ava-icon.ava-icon-daren {
background-position: -40px 0;
}
.u-avatar .ava-icon {
position: absolute;
right: -5px;
bottom: 0;
width: 12px;
height: 12px;
background-image: url(//s3.music.126.net/mobile-new/img/usericn_2x.png?6423c06…=);
background-repeat: no-repeat;
background-size: 75px auto;
}
.pylst_header .lsthd_auth {
display: block;
position: relative;
margin-top: 20px;
}
.lsthd_link {
display: inline-block;
color: hsla(0,0%,100%,.7);
}
.f-thide {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-break: normal;
}
.pylst_header .lsthd_num {
position: absolute;
right: 2px;
top: 0;
z-index: 3;
padding-left: 15px;
color: #fff;
font-size: 12px;
background-position: 0;
background-repeat: no-repeat;
background-size: 11px 10px;
text-shadow: 1px 0 0 rgba(0,0,0,.15);
}
.lsthd_fl:after {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 18px;
z-index: 2;
background-image: -webkit-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,.2));
background-image: linear-gradient(90deg,rgba(0,0,0,0),rgba(0,0,0,.2));
}
.u-earp {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAQAAABKfvVzAAABfUlEQVR4AZXSA0y/YRAH8PvbdhqyrbnmMDPXFIYwZmt2bo5jDRlDtu1mZHc9z737/Z7t4n833ffu8+p5Af+zePAZQ7AaB3AF57Ebq0X35X7wBhNxEXdZLWKSmNwB/mATW1XVjH84+IdD2nC/tyclLuC9u5l3QmBXyn6vlorpPwXkw7TK+HqjJ+WVG7iqeuXWlXK9QaQV3ygQQ+ubFVFiyRp+gRjBc3gLP0XnWh11vUkkRgc+45wMetPBBX7xzyiQS28agTmxSSBYtof9X9zg051f/vMXt8N+IqEErqpl05/Dr64KfvVnyx2xKcHFsGyKA+DZveBZob/cuRgigNui2YE/D/4Qf2hrm4D2peHdg+CdtoUKoC+OifLhq/pcgWt6JBylYIADfa4eabH0amW5jGJRHOjypfKrlaUyAuAif4LHgParaMAYnMHkMUBbxgh8wAHPFTin/+l0ggOWK9AYdzZzPl8bwwDPFQBHei17DlTOwVdwEMMvHPAc8D/rBs0Gmx5Y/w/0AAAAAElFTkSuQmCC');
}
.m-sgitem, .m-sgitem .sgfl {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.m-sgitem {
padding-left: 10px;
}
.m-sgitem .sgfr {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
position: relative;
}
.m-sgitem .sgfl {
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
width: 40px;
font-size: 17px;
color: #999;
margin-left: -10px;
}
.m-sgitem .sgchfl {
padding: 6px 0;
width: 0;
}
.m-sgitem .sgtl {
font-size: 17px;
}
.m-sgitem .sginfo {
font-size: 12px;
color: #888;
}
.m-sgitem .sgchply {
display: inline-block;
width: 22px;
height: 22px;
background-position: -24px 0;
}
.u-hmsprt {
background: url(//s3.music.126.net/mobile-new/img/index_icon_2x.png?5207a28…=) no-repeat;
background-size: 166px 97px;
}
.m-sgitem .sgchfl, .m-sgitem .sgfr {
-webkit-box-flex: 1;
-webkit-flex: 1 1 auto;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
}
.m-sgitem .sgchfr {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
padding: 0 10px;
}
.m-sgitem .sgalia {
color: #888;
margin-left: 4px;
}
.u-smtitle {
height: 23px;
line-height: 23px;
padding: 0 10px;
font-size: 12px;
color: #666;
background-color: #eeeff0;
}
listdetail页面样式
下一章介绍歌曲播放页面(唱片旋转,歌曲进度条,以及歌词滚动等效果)
仿网易云音乐-微信小程序开发的更多相关文章
- [干货教程]仿网易云课堂微信小程序开发实战经验
本篇文章想跟大家分享下:我们公司“湖北诚万兴科技”最近刚帮客户定制开发.目前已上线的“哎咆课堂”微信小程序的开发经验分享.首先大概介绍下这个小程序所涉及到的主要技术点:微信登录.微信支付.微信小程序F ...
- [Chat]实战:仿网易云课堂微信小程序开发核心技术剖析和经验分享
本Chat以一个我参与开发并已上线运营近2年——类似网易云课堂的微信小程序项目,来进行微信小程序高级开发的学习. 本场Chat围绕项目开发核心技术分析,帮助你快速掌握在线视频.音频类小程序开发所需要的 ...
- 微信小程序开发日记——高仿知乎日报(下)
本人对知乎日报是情有独钟,看我的博客和github就知道了,写了几个不同技术类型的知乎日报APP 要做微信小程序首先要对html,css,js有一定的基础,还有对微信小程序的API也要非常熟悉 我将该 ...
- 微信小程序开发日记——高仿知乎日报(中)
本人对知乎日报是情有独钟,看我的博客和github就知道了,写了几个不同技术类型的知乎日报APP要做微信小程序首先要对html,css,js有一定的基础,还有对微信小程序的API也要非常熟悉 我将该教 ...
- 微信小程序开发日记——高仿知乎日报(上)
本人对知乎日报是情有独钟,看我的博客和github就知道了,写了几个不同技术类型的知乎日报APP 要做微信小程序首先要对html,css,js有一定的基础,还有对微信小程序的API也要非常熟悉 我将该 ...
- 《云阅》一个仿网易云音乐UI,使用Gank.Io及豆瓣Api开发的开源项目
CloudReader 一款基于网易云音乐UI,使用GankIo及豆瓣api开发的符合Google Material Desgin阅读类的开源项目.项目采取的是Retrofit + RxJava + ...
- 微信小程序开发学习资料
作者:初雪链接:https://www.zhihu.com/question/50907897/answer/128494332来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...
- 微信小程序开发中的二三事之网易云信IMSDK DEMO
本文由作者邹永胜授权网易云社区发布. 简介 为了更好的展示我们即时通讯SDK强悍的能力,网易云信IM SDK微信小程序DEMO的开发就提上了日程.用产品的话说就是: 云信 IM 小程序 SDK 的能力 ...
- 我们的微信小程序开发
基于微信小程序的系统开发准备工作 腾讯推出微信小程序也有一段时间了,在各种行业里面也都掀起一阵阵的热潮,很多APP应用被简化为小程序的功能迅速推出,同时也根据小程序的特性推出各种独具匠心的应用,相对传 ...
- C# WPF 低仿网易云音乐(PC)歌词控件
原文:C# WPF 低仿网易云音乐(PC)歌词控件 提醒:本篇博客记录了修改的过程,废话比较多,需要项目源码和看演示效果的直接拉到文章最底部~ 网易云音乐获取歌词的api地址 http://music ...
随机推荐
- hadoop集群实现分发文件命令xsync脚本文件
1 #!/bin/bash 2 3 #1. 判断参数个数 4 if [ $# -lt 1 ] 5 then 6 echo Not Enough Arguement! 7 exit; 8 fi 9 10 ...
- Android---intent和startActivityForResult方法的使用---页面跳转和数据回传
Android页面跳转和数据回传 今天我尝试用两个页面实现数据的传递和回传,出现了一些问题,把问题已经成功的案例总结如下: 具体是这样的: 有两个layout布局,两个activity.MainAct ...
- Unity最新一键清理Prefab中所有MissingComponent
因为老的API Properties.DeleteArrayElementAtIndex(propertyIndex);提示没权限修改, 而unity提供了新的API GameObjectUtil ...
- #单调栈,树状数组#CF1635F Closest Pair
题目 设 \(f(x,y)=|a_x-a_y|*(w_x+w_y)\),其中 \(a\) 单调递增 多组询问求 \(\min_{l\leq l'<r'\leq r}\{f(l',r')\}\) ...
- #期望dp#51nod 2015 诺德街
题目传送门 分析 禁不住 QuantAsk 的诱惑(bushi) 考虑一条路线可以由若干段 \(1-2-\dots-n-\dots-2\) 以及 最后一段 \(1-\dots-x\) 组成. 对于最后 ...
- go~istio加载wasm的步骤
参考 https://github.com/higress-group/proxy-wasm-go-sdk/tree/main/proxywasm https://github.com/tetrate ...
- 战码先锋直播预告丨参与ArkUI,共建OpenHarmony繁荣生态
OpenAtom OpenHarmony(以下简称"OpenHarmony")工作委员会首度发起「OpenHarmony开源贡献者计划」,旨在鼓励开发者参与OpenHarmony开 ...
- openGauss/MogDB数据库安装部署之xlog目录设置
openGauss/MogDB 数据库安装部署之 xlog 目录设置 本文出处:https://www.modb.pro/db/176915 关于 xlog xlog 文件是一个记录事务日志的文件,它 ...
- 第一篇:Python入门基础
主要内容 1.Python简介 2.变量 3.字符编码 4.用户交互 5.if 流程判断 6.while循环 7.for循环 一.Python简介 1.python的创始人为吉多·范罗苏姆(Guido ...
- 基于 Java 编程生成二维码图片
0x01 准备 (1)软件版本 IntelliJ IDEA 2023.1.3 JDK 18 Tomcat 10.1.11 Maven 3.8.6 (2)技术栈 servlet zxing 谷歌项目 生 ...