打开微信公众平台 -> 注册账号 -> 下载开发工具 -> 创建项目
项目创建完成之后,在调试器里会报一个错误:云开发初始化错误
wx.cloud.init({
// env 参数说明:
// env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源
// 此处请填入环境 ID, 环境 ID 可打开云控制台查看
// 如不填则使用默认环境(第一个创建的环境)
env: 'dev-f2y9s',
// 是否在云开发控制台中记录访问过我们小程序的用户
traceUser: true,
})
tabBar
"pages": [
"pages/playlist/playlist",
"pages/blog/blog",
"pages/profile/profile"
],
"tabBar": {
"color": "#8a8a8a",
"selectedColor": "#d43c43",
"list": [
{
"pagePath": "pages/playlist/playlist",
"text": "音乐",
"iconPath": "./images/playlist.png",
"selectedIconPath": "./images/playlist_active.png"
},
{
"pagePath": "pages/blog/blog",
"text": "发现",
"iconPath": "./images/blog.png",
"selectedIconPath": "./images/blog_active.png"
},
{
"pagePath": "pages/profile/profile",
"text": "我的",
"iconPath": "./images/profile.png",
"selectedIconPath": "./images/profile_active.png"
}
]
},
借鉴的规范:https://github.com/airbnb/javascript
右键云函数 -> 创建并部署:云端安装依赖(不上传 node_modules)
onLoad: function (options) {
wx.cloud.callFunction({
name: 'login'
}).then((res) => {
console.log(res)
})
},
资源地址:
https://github.com/xiecheng328/miniprogram/tree/master/assets
1)数据
资源地址:https://github.com/xiecheng328/miniprogram/tree/master/assets
data: {
swiperImages: [{
url: 'http://p1.music.126.net/oeH9rlBAj3UNkhOmfog8Hw==/109951164169407335.jpg',
},
{
url: 'http://p1.music.126.net/xhWAaHI-SIYP8ZMzL9NOqg==/109951164167032995.jpg',
},
{
url: 'http://p1.music.126.net/Yo-FjrJTQ9clkDkuUCTtUg==/109951164169441928.jpg',
}
]
},
2)结构
在这里,循环写到了
标签内;在DOM中
不会渲染出来
<swiper class="swiper" indicator-dots="{{ true }}" autoplay="{{ true }}" interval="{{ 2000 }}" circular="{{ true }}">
<block wx:for="{{swiperImages}}" wx:key="{{ index }}">
<swiper-item>
<image class="bannerImg" src="{{item.url}}" mode="widthFix">image>
swiper-item>
block>
swiper>
新建组件
组件位置:miniprogram/components
新建组件:新建目录 -> 新建component
使用组件
注册组件
<!--
"usingComponents": {
"组件名": "组件路径"
}
-->
{
"usingComponents": {
"gx-playlist": "/components/playlist/playlist"
}
}
使用组件
<gx-playlist>gx-playlist>
初始化组件
新建组件 - 注册组件 - 初始化数据
给组件传值
组件中 - 接收父级传入的数据
/**
* 组件的属性列表
*/
properties: {
playItem: {
type: Object
}
},
使用父级传入的数据
<view class="playlist-container">
<image class="playlist-image" src="{{ playItem.picUrl }}">image>
<text class="playlist-count">{{ playItem.playCount }}text>
<view class="playlist-name">{{ playItem.name }}view>
view>
组件化开发中的数据监听器(格式化播放数量)
observers
Component({
observers: {
'some.subfield': function(subfield) {
// 使用 setData 设置 this.data.some.subfield 时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
subfield === this.data.some.subfield
},
'arr[12]': function(arr12) {
// 使用 setData 设置 this.data.arr[12] 时触发
// (除此以外,使用 setData 设置 this.data.arr 也会触发)
arr12 === this.data.arr[12]
},
}
})
Component({
observers: {
'some.field.**': function(field) {
// 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
// (除此以外,使用 setData 设置 this.data.some 也会触发)
field === this.data.some.field
},
},
})
Component({
observers: {
'**': function() {
// 每次 setData 都触发
},
},
})
// 数据监听器
observers: {
['playItem.playCount'](count) {
this.setData({
_count: this._filterCount(count, 2)
})
}
},
// 组件的初始数据
data: {
_count: ''
},
methods: {
/**
* 格式化逻辑部分
* num: 待转化的数字
* point:保留几位小数
*/
_filterCount(num, point) {
let numStr = num.toString().split('.')[0] // 舍弃小数点,并转成String
if (numStr.length < 6) {
return numStr
} else if (numStr.length >= 6 && numStr.length <= 8) {
return (num/10000).toFixed(point) + '万'
} else if(numStr.length > 8) {
return (num/100000000).toFixed(point) + '亿'
}
},
},
在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item
<view wx:for="{{array}}">
{{index}}: {{item.message}}
view>
Page({
data: {
array: [{
message: 'foo',
}, {
message: 'bar'
}]
}
})
使用 wx:for-item 可以指定数组当前元素的变量名,
使用 wx:for-index 可以指定数组当前下标的变量名:
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.message}}
view>
注意
svg
图片搜索:在线制作base64
随便找一个,打开,上传svg
图片,生成 base64 字符串
使用 将生成的字符串放到background: url()
里
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMiAyMCI+PGcgb3BhY2l0eT0iLjE1Ij48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiMwNDAwMDAiIGQ9Im0yMiAxNi43NzdjMCAxLjIzMy0xLjEyMSAyLjIzMy0yLjUwNiAyLjIzMy0xLjM4NCAwLTIuNTA2LTEtMi41MDYtMi4yMzN2LTIuNTUzYzAtMS4yMzQgMS4xMjItMi4yMzMgMi41MDYtMi4yMzMuMTc0IDAgLjM0My4wMTcuNTA2LjA0NnYtMS4zN2gtLjAzM2MuMDE3LS4yMi4wMzMtLjQ0MS4wMzMtLjY2NiAwLTQuNDE4LTMuNTgyLTgtOC04LTQuNDE4IDAtOCAzLjU4Mi04IDggMCAuMjI1LjAxNi40NDYuMDM0LjY2NmgtLjAzNHYxLjM3Yy4xNjMtLjAyOS4zMzMtLjA0Ni41MDUtLjA0NiAxLjM4NCAwIDIuNTA2Ljk5OSAyLjUwNiAyLjIzM3YyLjU1M2MwIDEuMjMzLTEuMTIyIDIuMjMzLTIuNTA2IDIuMjMzcy0yLjUwNS0uOTk5LTIuNTA1LTIuMjMzdi0yLjU1M2MwLS4yNTguMDU5LS41MDEuMTQ4LS43My0uMDg1LS4xNDgtLjE0OC0uMzEtLjE0OC0uNDkzdi0yLjY2N2MwLS4wMjMuMDEyLS4wNDMuMDEzLS4wNjctLjAwNC0uMDg4LS4wMTMtLjE3Ni0uMDEzLS4yNjYgMC01LjUyMyA0LjQ3Ny0xMCAxMC0xMCA1LjUyMyAwIDEwIDQuNDc3IDEwIDEwIDAgLjA5LS4wMDkuMTc4LS4wMTQuMjY2LjAwMi4wMjQuMDE0LjA0NC4wMTQuMDY3djJjMCAuMzA2LS4xNDUuNTY5LS4zNi43NTMuMjI0LjMzNC4zNi43Mi4zNiAxLjEzOHYyLjU1MiIvPjwvZz48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiNmZmYiIGQ9Im0yMCAxNi43NzdjMCAxLjIzMy0xLjEyMSAyLjIzMy0yLjUwNiAyLjIzMy0xLjM4NCAwLTIuNTA2LTEtMi41MDYtMi4yMzN2LTIuNTUzYzAtMS4yMzQgMS4xMjItMi4yMzMgMi41MDYtMi4yMzMuMTc0IDAgLjM0My4wMTcuNTA2LjA0NnYtMS4zN2gtLjAzM2MuMDE3LS4yMi4wMzMtLjQ0MS4wMzMtLjY2NiAwLTQuNDE4LTMuNTgyLTgtOC04LTQuNDE4IDAtOCAzLjU4Mi04IDggMCAuMjI1LjAxNi40NDYuMDM0LjY2NmgtLjAzNHYxLjM3Yy4xNjMtLjAyOS4zMzMtLjA0Ni41MDUtLjA0NiAxLjM4NCAwIDIuNTA2Ljk5OSAyLjUwNiAyLjIzM3YyLjU1M2MwIDEuMjMzLTEuMTIyIDIuMjMzLTIuNTA2IDIuMjMzcy0yLjUwNS0uOTk5LTIuNTA1LTIuMjMzdi0yLjU1M2MwLS4yNTguMDU5LS41MDEuMTQ4LS43My0uMDg1LS4xNDgtLjE0OC0uMzEtLjE0OC0uNDkzdi0yLjY2N2MwLS4wMjMuMDEyLS4wNDMuMDEzLS4wNjctLjAwNC0uMDg4LS4wMTMtLjE3Ni0uMDEzLS4yNjYgMC01LjUyMyA0LjQ3Ny0xMCAxMC0xMCA1LjUyMyAwIDEwIDQuNDc3IDEwIDEwIDAgLjA5LS4wMDkuMTc4LS4wMTQuMjY2LjAwMi4wMjQuMDE0LjA0NC4wMTQuMDY3djJjMCAuMzA2LS4xNDUuNTY5LS4zNi43NTMuMjI0LjMzNC4zNi43Mi4zNiAxLjEzOHYyLjU1MiIvPjwvc3ZnPg==);
arr: ['wxml', 'js', 'wxss', 'json']
; 则wx:key
建议使用wx:key="*this"
id
就好;使用每一项的id的时候,如果字段也是id
,不用写成wx:key="item.id"
,直接写成wx:key="id"
就好;index
说明:
async / await
是 Es7 的语法,如果在云函数中使用,云函数默认是支持的,因为云函数要求,node版本最低是 8.9,所以在云函数端async / await
是默认支持的;但是在小程序端,默认是不支持async / await
的,所以需要引入额外的文件,才能使小程序端支持;
说明:当我写这篇博客的时候,小程序已经支持
async / await
语法了
下面还是记录一下,如果不支持,我们该怎么处理;
1. 下载文件
地址:https://github.com/xiecheng328/miniprogram/tree/master/regenerator
将tuntime.js
文件,放到/miniprogram/utils
中
2. 引入文件
// 注意 regeneratorRuntime 不要变
import regeneratorRuntime from '../../utils/runtime.js'
然后就可以使用 async / await
语法了;
音乐数据是从第三方获取到的,每天都会有新的推荐的歌单,如果我只是一次获取的话,那我的歌单就只是那些数据,所以说,我们要给函数设置一个定时触发器,每天会有固定的时间去服务器上取数据,这样就能保证我每天取到的都是最新的数据;
取数据的时候,要和旧数据做一下比较,把数据库中没有的数据才插入到数据库中;
右键 cloudfunctions
->
新建 Node.js 云函数
->
getPlayList
yarn add axios
地址
http://musicapi.leanapp.cn/
推荐歌单 (get)
说明 : 调用此接口 , 可获取推荐歌单
可选参数 : limit: 取出数量 , 默认为 30 (不支持 offset)
接口地址 : /personalized
调用例子 : /personalized?limit=1
请求到数据
// 云函数入口文件
const cloud = require('wx-server-sdk')
// axios
const axios = require('axios')
const url = 'http://musicapi.leanapp.cn/personalized?limit=20'
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
const res = await axios.get(url)
console.log(res.data.result)
}
1)创建数据库集合
2)插入数据
https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/database/init.html
云数据库插入的时候只能单条插入,所以要循环遍历当前数组
// 云函数入口文件
const cloud = require('wx-server-sdk')
// axios
const axios = require('axios')
const url = 'http://musicapi.leanapp.cn/personalized?limit=20'
cloud.init()
// 数据库 - 要在初始化后面,因为有cloud,所以就不用wx.cloud了
const db = cloud.database()
// 云函数入口函数
exports.main = async (event, context) => {
const res = await axios.get(url)
if (res.data.result.length > 0) {
for (let i = 0; i < res.data.result.length; i++) {
await db.collection('playlist').add({
data: {
...res.data.result[i],
createTime: db.serverDate()
}
}).then((res) => {
console.log('Success', res)
}).catch((err) => {
console.log('Error', err);
})
}
}
}
注意:
cloud.init()
之后,因为能直接拿到cloud
,所以就不用wx.cloud.database()
引用了;const db = cloud.database()
– db.serverDate()
能获取到当前服务器的时间,在写入数据库数据的时候,添加上时间,方便做按时间排序操作await
当我再次调用 请求歌单数据并插入数据库 这个函数的时候,假设我读取到的还是这些数据,同样插入到数据库中,这样我对应的歌单信息就会有重复的数据,所以需要去重;
// 云函数入口函数
exports.main = async (event, context) => {
// 读取数据库中的歌单数据
const list = await db.collection('playlist').get();
// 读取服务器的歌单数据
const res = await axios.get(url)
const playList = res.data.result;
// 数组去重
const newData = []
for (let i = 0; i < playList.length; i++) {
let flag = true;
for (let j = 0; j < list.data.length; j++) {
if (playList[i].id === list.data[j].id) {
flag = false
break
}
}
if (flag) {
newData.push(playList[i])
}
}
// 循环数据并插入数据库
if (newData.length > 0) {
for (let i = 0; i < newData.length; i++) {
await db.collection('playlist').add({
data: {
...newData[i],
createTime: db.serverDate()
}
}).then((res) => {
console.log('Success', res)
}).catch((err) => {
console.log('Error', err);
})
}
}
}
当我们去获取云数据库中某一个集合的所有数据的时候,其实是有对应的条数限制的,如果我们在云函数中获取,那么每次最多获取100条,如果是在小程序端获取,每次最多获取20条数据;
随着时间推移,歌单的数量会不断增多,所以100条数据很明显不会满足需求;这里就说一下如何突破100条的条数限制;
需要优化的,就是这一行代码
// 读取数据库中的歌单数据
const list = await db.collection('playlist').get();
思路:假设当前我的数据库中有210条数据,如果每次只能取100条的话,我取三次就能把这210条数据取完,然后把这三次的数据拼装成一个数组,这个数组的数据就是全部的数据;
skip: https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/database/collection/Collection.skip.html
// 每次能获取的最大数量
const MAX_COUNT = 10;
// 获取歌单条数
const countResult = await db.collection('playlist').count();
const total = countResult.total
// 要获取的次数(向上取整)
const batchTimes = Math.ceil(total / MAX_COUNT)
// 所有的歌单数据数组
const list = []
for (let i = 0; i < batchTimes; i++) {
const arr = await db.collection('playlist').skip(i * MAX_COUNT).limit(MAX_COUNT).get()
list.push(...arr.data);
}