本文记录如何从零开始如何一步步完成云开发小程序。该小程序分为tabBar页面、基础页面;页面中包含封装的自定义组件,使用第三方组件库vant协助开发;通过云函数更新修改数据库,开发具体流程见下:
项目前期准备工作
-
编写全局wxss文件,设置小程序整体的样式。如
height: 100%;、box-sizing: border-box; -
自定义tabBar。
-
修改app.json文件配置
-
创建custom-tab-bar文件夹,按照自定义组件的形式编写四个文件。
-
该组件展示时,使用vant组件库中的Tabbar标签栏。
-
绑定change事件。当标签栏发生变化时触发该事件,实现页面跳转。
默认情况下,event.detail拿到当前选中项的索引;标签指定name的情况下,event.detail拿到当前选中项的name。
-
-
vant组件库。
- 下载包
npm i @vant/weapp -S --production - 修改app.json文件配置
- json文件中引入,wxml文件中使用。
- 下载包
-
云开发。
-
修改project.config.json文件配置;
编写全局app.js文件,在onLaunch函数中,通过
wx.cloud.init({})手动指定环境; -
下载包
npm install wx-server-sdk; -
如果需要导入数据库的话,点击云开发控制台,点击数据库,新建集合,点击导入文件。
三个集合。userInfo、animal、goods。
-
新建cloud文件夹,新建Node.js云函数文件夹,编写函数,上传到服务器。
-
封装自定义组件
-
每个宠物的基本信息animal-card组件
-
该组件展示宠物的基本信息,组件用到原生标签slot插槽标签;vant组件库中van-tag标记组件。
该整体组件绑定tap点击事件,进行页面跳转,跳转到宠物详细信息页面。未传参。
设置插槽,使自定义组件更加自由。
-
js文件中。
- options配置对象中,开启多插槽。
- 在properties中设置父组件传递过来的参数类型。
-
页面跳转的函数。
- 使用wx.navigateTo方法
- 跳转到宠物详细信息页面,把当前宠物id传过去。url采取模板字符串的形式。
-
-
每个商品信息goods-card组件
-
该组件展示商品信息,组件用到原生标签radio标签;vant组件库中van-card商品卡片组件、van-stepper步进器组件。
两栏flex布局,左边是单选按钮,右边是card。
radio标签有是否选中、禁用等属性;绑定tap点击事件,更改当下商品是否选中状态的函数。
van-card商品卡片组件有图片thumb、标签tag等属性;使用插槽,
slot="num",插槽中放入van-stepper步进器组件,可自定义van-card的结构。van-stepper步进器组件有最小值、最大值、步长、禁用、value等属性;受控组件,实现双向数据流:绑定change事件,更改当下商品数量。value的值为data中的数据,当输入框中的value改变时触发函数,通过e.detail得到value的值,实时改变data中的数据,进而实时更新标签中value属性的值。
-
在properties中设置父组件传递过来的参数类型。
-
更改当下商品是否选中状态的函数。
-
商品是否选中状态取反,更新当下商品对象。
-
通过this.triggerEvent()方法触发父组件传递的自定义事件,并向父组件传递参数,如该商品id、商品是否选中状态、商品数量。
父组件中更新整个goodsList商品列表。
-
-
更改当下商品数量的函数。
-
当输入框中的value改变时触发函数,通过e.detail得到value的值,实时改变data中的数据,进而实时更新标签中value属性的值,更新当下商品对象。
-
通过this.triggerEvent()方法触发父组件传递的自定义事件,并向父组件传递参数,如该商品id、商品是否选中状态、商品数量。
父组件中更新整个goodsList商品列表。
-
-
tabBar页面
-
首页home
-
配置json文件。窗口的背景颜色、窗口的标题、窗口的标题字体颜色;引入vant组件库中van-button组件;宠物基本信息animal-card组件。
-
展示页面用到原生组件scroll-view、swiper;vant组件库中van-button;自定义组件ani-card组件。
scroll-view组件设置scroll-view固定高度、绑定scrolltolower上拉触底加载事件、refresherrefresh下拉刷新事件。
van-button组件绑定tap/click点击事件,选择宠物类型的函数。通过data-xx传参,把宠物类型作为参数传递给事件对象。
自定义组件ani-card组件中,父组件向子组件传递数据。列表渲染,多个父组件并列排布。
-
onLoad函数中。
- 修改tabBar组件中data中的 active属性。
- 动态获取窗口高度,减去Tabbar组件高度,动态计算得到scroll-view高度,更新到data中。
- 调用获取宠物列表函数。
-
获取宠物列表函数。
- 调用getAnimalList云函数,传入参数为宠物类型、当前页码、每页展示数据的数量,并得到宠物列表;宠物列表更新到data中。
- 若刷新被开启,需要手动关闭刷新。
-
cloud文件夹中编写getAnimalList云函数,返回宠物列表,数组的形式。
- 在animal集合中,用到where()、limit()、skip()、get()方法,参数为宠物类型、当前页码、每页展示数据的数量,获取宠物列表。
-
上拉触底加载事件,后台分页,减轻服务器和用户压力。调用获取宠物列表函数。
-
下拉刷新事件。调用获取宠物列表函数。
-
选择宠物类型事件。通过data-xx传参,通过event.currentTarget.dataset.xx获得参数。调用获取宠物列表函数。
-
-
个人中心页mine
-
展示页面用到vant组件库中van-notice-bar通知栏、van-cell单元格、van-cell-group。
button标签,属性open-type="chooseAvatar",点击可实现选择头像功能,绑定chooseavatar用户选择头像事件。
button标签中包含image标签,用户未登录时,显示灰色头像,头像地址在data中。
van-cell单元格组件绑定tap/click点击事件,进行页面跳转。通过data-xx传参,把路径作为参数传递给事件对象。
-
onLoad函数中修改tabBar组件中data中的 active属性。
-
用户选择头像事件。
- event.detail拿到用户信息,event.detail.avatarUrl拿到头像。
- 调用login云函数,传入参数为用户头像,得到该用户信息。返回结果存储在本地存储中;返回结果更新到data中。
-
cloud文件夹中编写login云函数,返回该用户信息。
- 查询用户是否登录,用到where()、get()方法。
- 用户未登录,需要添加注册用户信息,用到add()方法。
- 用户已登录,需要获取用户信息,用到doc()、get()方法。
-
获取用户信息的函数。
- 每次显示个人中心页,都需要获取最新的用户信息,从数据库中取出最新的个人信息,更新到data中。
- 数据库中取出最新信息,用到doc()、get()方法,参数为用户id。
-
页面跳转的函数。封装函数,统一实现页面跳转。
- 使用wx.navigateTo方法。
- 通过data-xx传参,通过event.currentTarget.dataset.xx获得参数,分别跳转到我的云养、我的关注、个人资料页面。
-
退出登录的函数。清空浏览器本地存储,删除data中数据,但不会影响数据库。
-
基础页面
-
宠物详细信息页面animalInfo
-
展示宠物的详细信息,组件用到原生组件轮播图swiper、vant组件中的van-button、van-icon、商品导航van-goods-action/van-goods-action-icon/van-goods-action-button组件。
van-button组件的属性open-type="share",点击按钮可以实现转发功能。
van-goods-action-icon图标组件绑定click点击事件,返回首页。未传参。
van-goods-action-icon图标组件绑定click点击事件,关注/取消关注。未传参。
van-goods-action-button按钮组件绑定click点击事件,跳转到云养支付页面。未传参。
-
onLoad函数中。
- 拿到自定义组件animal-card跳转到宠物详细信息页面时,路由传过来的宠物id,更新到data中。
- 拿到本地存储中的用户id,更新到data中。
- 调用获取宠物详情函数。
- 设置当前页面的转发按钮。设置为发送给朋友、分享到朋友圈。
-
用户点击关注 || 取消关注函数。
- 用户已登录,提示用户操作中;调用patchLike云函数,更改该用户信息,无返回值;调用获取宠物详情函数;关闭提示。
- 用户未登录,提示用户登录,返回函数。
-
cloud文件夹中编写patchLike云函数,更新该用户信息。
-
在userInfo集合中获取该用户信息的JSON对象数据,用到doc()、get()方法,参数为用户id。
-
在userInfo集合中更新该用户信息的JSON对象数据,用到doc()、update()方法,参数为用户id。
用户信息JSON对象中添加likeAnimalIds属性,属性值为关注宠物的id的数组,更新方法无返回值。
利用数组的includes()方法判断数组中是否包含该宠物id。如果likeAnimalIds数组中有该宠物id,则取关,利用数组的filter()方法,筛选出不是该宠物id的宠物们;如果ikeAnimalIds列表里没有该宠物id,则关注该宠物,利用ES6的语法,数组中增加该元素。
-
该云函数返回静态数据,message、code等。
-
-
获取宠物详情函数。
- 用户已登录,调用getAnimalInfo云函数,传入参数如该用户id、该宠物id,得到该animalId宠物的详细信息 + like属性。
- 用户未登录,用到doc()、get()方法,参数为该宠物id,获取该animalId宠物的详细信息。
- 宠物的详细信息更新到data中。
-
cloud文件夹中编写getAnimalInfo云函数,返回该animalId宠物的详细信息 + like属性。
-
在userInfo集合中获取该用户信息的JSON对象数据,用到doc()、get()方法,参数为用户id。
在animal集合中获取该宠物信息的JSON对象数据,用到doc()、get()方法,参数为宠物id。
-
返回该animalId宠物的详细信息,并添加like属性。like属性的值为布尔值,表示该用户的likeAnimalIds数组中是否含有该宠物id。
-
-
返回首页函数。返回之前某个tabBar页面,即主页,用wx.switchTab()方法。
-
进入云养支付页面函数。
- 用户已登录,wx.navigateTo()方法。宠物详情页面跳转到云养支付ralsePay页面,把当前宠物id传过去。
- 用户未登录,提示用户登录。
-
当用户用户点击按钮分享、用户点击页面右上角分享时,自定义分享内容。
-
title;path是被分享者进入小程序时的页面。
分享时传递该宠物id,进入页面后onLoad执行,获取宠物详情函数正常调用,才能正常显示宠物信息。
-
-
-
云养支付页面ralsePay
-
展示页面用到原生标签radio单选框;vant组件库中的van-image、van-tag标记、van-submit-bar提交订单栏;自定义组件ani-goods-card。
ani-goods-card自定义组件中。
- 父组件向子组件传递数据。列表渲染,多个父组件并列排布。
- 绑定setCheckedNum自定义事件,父向子传递函数,子中触发函数并传递参数给父。
van-submit-bar提交订单栏组件有价格、按钮文本等属性;绑定submit提交事件,提交订单,进行支付的函数;包含radio标签。
radio标签有是否选中等属性;绑定tap点击事件,点击全选按钮的函数。
-
onLoad函数中。
- 拿到宠物详细信息页面跳转到云养支付页面时,路由传过来的宠物id,更新到data中。
- 拿到本地存储中的用户id,更新到data中。
- 调用获取该宠物信息函数。
- 调用获取商品列表函数。
-
获取该宠物信息函数。
- 用到doc()、get()方法,参数为该宠物id,获取该animalId宠物的详细信息;更新到data中。
-
获取商品列表函数。
-
调用getGoodsList云函数,未传参,查询全部商品,得到所有商品的数组/列表。
-
对商品列表进行二次处理。利用数组forEach()方法遍历商品列表,为数组中每一项元素item设置checked属性为false、value属性为1。
初始情况下,每个商品为未选中状态,选择数量为1。
-
商品列表更新到data中。
-
-
cloud文件夹中编写getGoodsList云函数。
在goods集合中,用到where()、get()方法,参数为{},查询全部商品,返回所有商品的数组/列表。
-
点击全选按钮的函数。
- 取出全选按钮的状态,对状态取反。
-
利用数组forEach()方法遍历商品列表,如果商品的库存数量amount大于0,该商品的选中状态和全选按钮状态设为一致。
- 全选按钮的状态、商品列表更新到data中。
- 调用计算价格函数。
-
自定义事件setCheckedNum。作用是某个商品的选中状态、数量变化时,更新整个goodsList商品列表,并重新计算价格。
- 通过event.detail获取子组件ani-goods-card自定义组件传递的参数,包括商品id、商品是否选中状态、商品数量value。
-
利用数组forEach()方法遍历商品列表,更新整个goodsList商品列表。
- 调用计算价格函数,重新计算价格。
-
计算价格函数。
- 利用数组forEach()方法遍历商品列表,如果选中了该商品,总价上增加该商品的价格乘以数量。
-
提交订单,进行支付的函数。
- 利用数组filter()方法遍历商品列表,筛选出选中的商品,返回新数组。
-
利用数组map()方法遍历新数组,每个商品对象变成一个新对象,对象中包含_id商品id、value商品数量,返回新数组payData。
- 如果新数组payData长度大于0,调用postPay云函数,传入参数为该用户id、该宠物id、payData、前端计算总价,获取返回结果包括code和message。
- 根据返回结果中的message提示用户;根据返回结果中的code若为真,通过wx.redirectTo()方法跳转到我的云养myCloudRalse页面。
-
cloud文件夹中编写postPay云函数,返回静态结果如code、message。
-
在userInfo集合中获取该用户信息的JSON对象数据,用到doc()、get()方法,参数为用户id。
-
利用数组map()方法遍历payData数组,将每个对象变成每个商品的id,返回新数组ids。
-
在goods商品集合中找出符合新数组ids的所有数据,即用户选择想要购买商品们的数组,用到where()、db.command.in()、get()方法,参数为新数组ids。
返回结果解构出data,是数组的形式,每个数组元素是商品对象。
-
利用数组filter()方法遍历data数组,方法中利用数组find()方法遍历payData数组,找到同一商品,筛选出前台选择商品数量大于后台商品库存数量的商品,若筛选数组的长度大于0,返回静态结果,code为0,message为商品不足。
-
利用数组reduce()方法遍历data数组,方法中利用数组find()方法遍历payData数组,找到同一商品,通过后台商品的价格乘以前台选择商品数量,计算商品的后台总价,累加返回结果。
若商品的后台总价和前端计算总价不相等,返回静态结果,code为0,message为商品信息发生变化请重新支付。
若商品的后台总价大于用户余额,返回静态结果,code为0,message为支付失败,余额不足。
-
更新该用户信息,余额自减,爱心值自增。用到doc()、update()、db.command.inc()方法,参数为后台总价。
-
更新商品数据库,每个商品库存数量自减。
利用数组map()方法遍历payData数组,对每个数组元素用到doc()、update()、db.command.inc()方法,参数为前台选择商品数量,每个数组元素返回一个promise对象,map()方法返回promise数组。Promise.allSettled() 方法处理promise数组,更新商品数据库。
-
该云函数中调用patchRalse云函数,更新该用户信息,传入参数为该用户id、该宠物id,无返回值。
-
返回静态结果,code为200,message为支付成功。
-
-
cloud文件夹中编写patchRalse云函数,更新该用户信息。
-
在userInfo集合中获取该用户信息的JSON对象数据,用到doc()、get()方法,参数为用户id。
-
在userInfo集合中更新该用户信息的JSON对象数据,用到doc()、update()方法,参数为用户id。
用户信息JSON对象中添加cloudRalse属性,属性值为云养宠物的id的数组,更新方法无返回值。
在数组后添加新云养的宠物id,需要去重,set对数组去重后为set对象,Array.from把set对象转换为数组。
-
返回更新后的该用户信息。
-
-
-
我的云养页面myCloudRalse
-
展示页面用到vant组件库中的van-search搜索框、van-icon、van-tag、van-empty空状态;自定义组件ani-card组件。
van-search搜索框通过model:value实现简易双向数据流,可同时实时更新data、输入框中的value值;绑定search事件,用户点击键盘上的搜索或回车时触发;使用插槽,表示搜索框右侧按钮,插槽标签中绑定tap点击事件,用户点击搜索按钮时触发。
如果用户未登录,展示van-empty空状态组件;如果用户已登录,未云养宠物,展示van-empty空状态组件;
如果用户已登录,已云养宠物,展示ani-card自定义组件,包含van-icon、van-tag组件。
- 父组件向子组件传递数据。列表渲染,多个父组件并列排布。
- 其中van-icon、van-tag组件中使用自定义组件中的插槽。
-
onShow函数中。因为每次进入我的云养页面,都希望展示最新数据,所以在onShow函数中调用函数。
- 拿到本地存储中的用户id,更新到data中。也顺便放在onShow函数中。
- 调用我的云养函数。
-
我的云养函数。
- 用户点击键盘上的搜索或回车时、用户点击搜索按钮时、onShow函数中调用时触发。
- 调用getRalseList云函数,传入参数为用户id、搜索框中的内容,得到云养宠物列表,数组的形式,更新到data中。
-
cloud文件夹中编写getRalseList云函数,返回云养宠物列表,数组的形式。
- 在userInfo集合中获取该用户信息的JSON对象数据,用到doc()、get()方法,参数为用户id。
- 在animal集合中,用到where()、db.command.in()、get()方法,参数为用户信息中的云养数组cloudRalse、正则匹配对象,返回云养宠物列表,数组的形式。
-
-
我的关注页面myLike
-
展示页面用到vant组件库中的van-button、van-icon、van-tag、van-empty空状态;自定义组件ani-card组件。
van-button组件中,icon图标是动态变化的,若降序排序则为向下箭头,若升序排序则为向上箭头;绑定tap点击事件,切换排序规则的函数。
如果用户未登录,展示van-empty空状态组件;如果用户已登录,未关注宠物,展示van-empty空状态组件;
如果用户已登录,已关注宠物,展示ani-card自定义组件,包含van-icon、van-tag组件。
- 父组件向子组件传递数据。列表渲染,多个父组件并列排布。
- 其中van-icon、van-tag组件中使用自定义组件中的插槽。
-
onShow函数中。因为每次进入我的专注页面,都希望展示最新数据,所以在onShow函数中调用函数。
- 拿到本地存储中的用户id,更新到data中。也顺便放在onShow函数中。
- 调用我的关注函数。
-
切换排序规则的函数。
- 对data中的排序规则取反,更新到data中。
- 调用我的关注函数。
-
我的关注函数。
调用getLikeList云函数,传入参数为用户id、排序规则,得到关注宠物列表,数组的形式,更新到data中。
-
cloud文件夹中编写getLikeList云函数,返回关注宠物列表,数组的形式。
- 在userInfo集合中获取该用户信息的JSON对象数据,用到doc()、get()方法,参数为用户id。
- 在animal集合中,用到where()、db.command.in()、orderBy()、get()方法,参数为用户信息中的关注数组likeAnimalIds、排序规则,返回关注宠物列表,数组的形式。
-
-
个人资料页面myInfo
-
展示页面用到原生组件image、vant组件库中的van-field输入框、van-cell-group包裹输入框、van-button。
image标签绑定tap点击事件,选择图片作为头像。
van-field输入框通过model:value通过model:value实现简易双向数据流,可同时实时更新data、输入框中的value值。
van-button组件绑定tap点击事件,提交信息,作用是更改服务端的用户昵称和用户头像。
-
onLoad函数中。
- 拿到本地存储中的用户id,更新到data中。
- 调用获取用户信息函数。
-
获取用户信息函数。
在userInfo集合中获取该用户信息的JSON对象数据,用到doc()、get()方法,参数为用户id。将返回数据的头像地址、昵称更新到data中。
-
选择图片作为头像的函数。
通过
wx.chooseMedia()方法从手机相册中或拍摄中,选择图片,返回结果为buffer流形式的图片临时地址,更新到data中。 -
提交信息的函数。
-
比较服务端头像和当前页面头像,判断是否修改了头像。
若修改通过
wx.getFileSystemManager().readFileSync(xxx)将buffer流形式的图片临时地址转换为arrayBuffer流。 -
提示用户正在操作中。
-
调用patchUserInfo云函数,传递参数为用户id、用户昵称、用户头像,更新该用户信息,无返回值。
-
关闭提示,通过
wx.navigateBack()方法返回上一页。
-
-
cloud文件夹中编写patchUserInfo云函数,更新该用户信息。
-
得到前端传递的数据,用户id、用户昵称、用户头像。
在userInfo集合中获取该用户信息的JSON对象数据,用到doc()、get()方法,参数为用户id。
通过用户头像数据是否为空,判断用户是否修改了头像。若修改通过
cloud.uploadFile()方法上传新头像,参数是对象的形式,包含cloudPath、fileContent属性;通过cloud.deleteFile()方法删除旧头像,参数是对象的形式,包含fileList属性;新头像赋值到该用户信息的头像属性。 -
在userInfo集合中,通过doc()、update()方法,更新该用户信息中的用户昵称、用户头像。
-
返回该用户信息。
-
-
采坑修复
- 改变数据库中某个集合的权限,创建者可读写改为所有用户可读,创建者可读写。这样未登录的用户也可以看到信息。
- 服务类目设置为工具-信息查询,小程序上线。
- 首页不显示,审核未通过,在设置中勾选“不校验合法域名、web-view(业务域名)、TSL版本以及HTTPS证书”。