这篇文章会很长,十分长,特地长,无敌长。
真的是挤牙膏般的我的项目进度,差不多是8月底有开始这个我的项目的想法,时至今日都1个多月了,抛去频繁的加班工夫,王者工夫,羽毛球工夫...见缝插针的写这个我的项目,我居然写完了,我居然没有半途放弃,可真把我本人打动坏了。
好吧,次要是这个小程序很简略,本文会解说一下这个小程序的代码,所有代码简直是我一个个敲进去的,所有逻辑也是本人构思梳理的,因而很多实现形式并不是很好,冗余代码很多,代码品质堪忧,但我也在学习中,随着技术晋升,会一直来重构代码,如果大家有任何倡议欢送私信我哦,特别感谢。
该小程序采纳的云开发,没有本人搭建后端,我心目中,只有没有后端的内容我就感觉很简略。但其实我还是想有朝一日能本人独立实现前后端所有工作,写一个更棒的作品。
之前有写过几篇文章,能够回顾一下。你可能须要的文章:
- 微信小程序自定义导航栏
- 微信小程序中应用iconfont
- 微信小程序云开发图片资源援用
- 微信小程序启动页的实现
- 微信小程序应用WeUI组件库
天啦噜,看了半天代码发现还挺多,一时间不知道该从哪里开始。那还是依照tab页应用逻辑程序来吧。
启动页
之前文章也有过如何写一个启动页面。至于为什么须要个启动页呢?
我感觉次要也就两点,一个是难看,还有个就是增加获取用户信息类型按钮,间接疏导用户受权获取用户信息。
至于为啥要获取用户信息?
曾真有段时间,我纠结了良久,因为我本人这个程序中,除了展现,如同也没啥须要用到这个数据的中央。
但我还是写了。
以后登陆用户的用户名和头像图片,通过 open-data 标签能够无需受权间接获取,只有指定相应类型userNickName和userAvatarUrl即可,款式只须要用view容器包裹起来进行设置。button按钮指定open-type为getUserInfo,在点击事件中就能够拿到受权之后的用户公开信息数据。
拿到用户信息须要保留到数据库中,也只须要首次登录的用户在受权之后才须要入库,所以加个判断以后登陆用户是否是首次登录,判断条件是每个用户的惟一值openId。
通过这个逻辑,那须要解决的能够分为如下几个:
1、获取以后登录用户的openId。
getOpenID() { let that = this; wx.cloud.callFunction({ name: 'login', complete: res => { const openId = res.result.event.userInfo.openId; that.setData({ openId }) } })},
这个login云函数是我的项目构建时主动生成的,云函数写法:
const cloud = require('wx-server-sdk')cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV})exports.main = async (event, context) => { const wxContext = cloud.getWXContext() return { event, openid: wxContext.OPENID, appid: wxContext.APPID, unionid: wxContext.UNIONID, env: wxContext.ENV, }}
2、获取数据库中所有用户数据。
getUsersList() { const that = this; db.collection('users').get({ success: res => { that.setData({ usersList: res.data, }) }, fail: console.error })},
3、在页面刚加载的时候调用下面两个办法,拿到openId和userList。在点击按钮时,查看以后登录用户是否曾经存在数据库。
goToIndex(e) { const that = this; const auth = e.detail.errMsg; wx.switchTab({ url: '/pages/index/index', }); if(auth === "getUserInfo:ok") { const avatarUrl = e.detail.userInfo.avatarUrl; const nickName = e.detail.userInfo.nickName; that.checkUser(nickName, avatarUrl); }},
这里获取到用户信息数据是这个样子滴:
4、查看以后登录用户是否曾经存在数据库。
checkUser(name, url) { const that = this; const list = this.data.usersList; const openId = this.data.openId const ids = []; list.forEach((item) => { ids.push(item._openid); }) if(ids.indexOf(openId) === -1) { that.setUserInfo(name, url) } else { return; }},
5、如果不存在的话,将该用户信息存入数据库users中。管它有用没用,先存着呗。
setUserInfo(name, url) { db.collection('users').add({ data: { nickName: name, avatarUrl: url, } })},
数据库中会主动给这个字段生成一个id和openId。
首页
首页从上到下分为几块,轮播图,轮播告示,icon列表,举荐商品展现。
轮播图。
间接用自带的组件,swiper和swiper-item配合应用。
<swiper class="swiper-top" indicator-dots="true" indicator-active-color="#fff" autoplay circular> <swiper-item wx:for="{{bannersList}}" wx:key="item"> <image mode="aspectFill" data-url="{{item}}" src="{{item}}" /> </swiper-item></swiper>
图片数据来自数据中定义好的。
getBannerList() { db.collection('banners').get({ success: res=> { this.setData({ bannersList: res.data[0].imgs, }) }, fail: console.error })}
轮播告示。
和轮播图一样的,只是轮播方向不同,swiper中增加个参数 vertical。点击显示弹窗,援用的是WeUI库,咋用参考以往文章。
icon列表。
到这里就要用到本程序中最最最简单的一个数据库汇合了,简直所有的商品数据都是寄存在这个汇合中的。
那icon列表就是获取goods汇合中每个对象icon字段值,举荐商品列表就是每个对象中list数组中所有isHot为true的数据。
getIconList() { const that = this; const arr = []; db.collection('goods').get({ success: res=> { const list = res.data; list.forEach((item) => { item.list.forEach((d) => { if(d.isHot) { const param = { ...d, categoryId: item._id }; arr.push(param); } }) }) that.setData({ categories: list, goodsRecommend: arr }) }, fail: console.error })},
给每个icon图片上加一个跳转到分类页的点击事件,个别的跳转能够应用wx.navigateTo,而tab页的跳转只容许应用wx.switchTab,官网文档中指明这个办法是不能够后缀参数的。
而我这里必定是须要点击不同的icon跳转到不同的分类栏目中的,那就须要在跳转时候携带该分类id,还是以后这个数组的下标。
通过定义全局参数,能够解决wx.switchTab无奈携带参数的问题。
app.js中,在onLaunch里定义个全局对象。
this.globalData = { categoryParamId: 0, categoryParamIndex: 0,}
商品分类页
在menu.js中,在最开始须要引入全局变量。
const app = getApp()
那下面定义的globalData能够间接通过app拿到。
分类页这儿次要的解决逻辑有三块内容。
1、辨别管理员权限和普通用户权限。
管理员权限能够有新增商品和删除的性能,普通用户只能够查看。
权限这块的解决应该会有更好的计划。
我比拟挫,想到的最简略的办法就是利用openId来做过滤。在页面首次加载的时候获取以后用户的openId,和启动页一样的办法,只是回调函数中不一样。在数据库中定义个管理员汇合,你须要给那些用户设置成管理员,将他们的openId放在这个汇合中。
我是在app.js中获取这个管理员汇合的,可能是刚刚尝过全局变量的苦头吧。
wx.cloud.database().collection('adminList').get({ success: res => { this.adminList = res.data[0].admin_openId; },})
那在menu.js中能够间接拿到这个adminList中数据,判断一下以后登录用户的openId在不在adminList中。
getOpenID() { let that = this; wx.cloud.callFunction({ name: 'login', complete: res => { const openId = res.result.event.userInfo.openId; if(app.adminList.indexOf(openId) === -1) { that.setData({ isAdmin: false }) } else { that.setData({ isAdmin: true }) } } })},
2、将设置成喜爱状态的商品数据存入本地缓存。
过后对于这个逻辑解决的思考也是想了蛮久,这个小程序的制作出发点只是作为一个助手作用,不便用户查看店铺所有商品,是做一个商品分类展现的性能,不领取线高低单,次要也是因为显示下单这个性能太简单,集体小程序没权限做。
那我就想着仅仅分类展现并不满足应用,退出个喜爱列表实用性更大。
商品的固定数据是能够存入云开发的数据库中,然而针对于每个用户不同的喜爱数据,最好的计划就是应用缓存。
localStorange的数据模式是key / value,一开始打算的是固定一个key,value中是个数组对象。
这肯定是可行的,但我不会做......麻烦能实现的敌人私信我。
好的计划来不了能够来挫的嘛。我用商品的分类Id和以后商品Id拼接起来作为key,这就保障了key唯一性,那存入本地的数据是须要在喜爱列表展现的,我须要展现的数据有分类Id,id,商品名,是不是喜爱,封面缩略图,价格。明确了这几点要求,实现就很简略了。
在每个商品的爱心图标上加一个点击事件。
joinFavorites(e) { const that = this; const id = e.currentTarget.dataset.id; const index = e.currentTarget.dataset.index; const list = this.data.goodsList[this.data.curIndex].list; const loveList = []; list.forEach((item) => { if (item.id === id) { item.isLove = !item.isLove; } const param = { categoryId: this.data.curNav, id: item.id, name: item.goodsName, isLove: item.isLove, thumbnail: item.imgs[0], price: item.newPrice }; loveList.push(param); }) that.setData({ goodsList: this.data.goodsList, }) // 缓存的key以分类id和服装id用-连贯 const key = loveList[index].categoryId + "-" + loveList[index].id; this.saveLocally(key, loveList[index]);},// 存入本地缓存saveLocally(key, data) { wx.setStorage({ key, data, })},
当初看这个代码,我感觉还是能够再重构优化的更好的。
3、从本地缓存中获取喜爱列表详情
有些商品是曾经退出喜爱列表的,商品上的喜爱图标曾经是高亮状态,等到下次进入该分类页,就应该将之前设置喜爱状态的商品显示进去,不然每次进来都是初始的模样就毫无意义了。
首先是须要获取商品列表数据,再依据本地缓存数据,将喜爱的商品数据批改一下状态。
这样就是分三步走。
获取商品列表数据。
getGoodsList() { const that = this; db.collection('goods').get({ success: res => { const list = res.data; that.getDetails(that.data.storageData, list); that.setData({ goodsList: list, }) } })},
读取缓存数据。
getLocally() { const that = this; wx.getStorageInfo({ success(res) { if (res.currentSize > res.limitSize) { that.setData({ isDialog: true }) } else { that.setData({ storageData: res.keys }) } }, })},
从本地缓存中获取喜爱列表详情。
getDetails(localArr, goodsList) { const that = this; localArr.forEach((localItem) => { const itemPId = localItem.split("-")[0].toString(); const itemId = localItem.split("-")[1].toString(); goodsList.forEach((goodItem) => { if (itemPId === goodItem._id) { goodItem.list.forEach((item) => { if (itemId === item.id.toString()) { wx.getStorage({ key: localItem, success(res) { item.isLove = res.data.isLove that.setData({ goodsList, }) } }) } }) } }) })},
次要的解决逻辑就是以上这三块。还有些其余的交互办法,商品分类的切换,详情页跳转,商品删除......这些就不写了,能够去看代码,都很容易了解的。
商品详情页
点击跳转过来的时候,携带的参数只有分类id和商品id。依据这两个字段就能够在商品列表数据查问到具体所有数据。
在以后页面获取传参过去的数据。
onLoad: function (options) { this.setData({ categoryId: options.categoryId, id: options.id });}
新增商品页
依照之前数据库汇合中定义的数据格式,这里就分两块。一个是相干数据的填写表单,一个就是上传的图片列表。
图片列表上传的实现,官网都给了相应的api办法。
抉择图片:
wx.chooseImage({ sizeType: ["original", "compressed"], // 能够指定是原图还是压缩图,默认二者都有 sourceType: ["album", "camera"], // 能够指定起源是相册还是相机,默认二者都有 success: function (res) { // 返回选定照片的本地文件门路列表,tempFilePath能够作为img标签的src属性显示图片 var tempFilePaths = res.tempFilePaths; var imgs = that.data.imgs; for (var i = 0; i < tempFilePaths.length; i++) { if (imgs.length >= 9) { that.setData({ imgs: imgs, }); return false; } else { const filePath = res.tempFilePaths[i]; var timestamp = Date.parse(new Date()); const cloudPath = `${timestamp}-${i}`; const param = { cloudPath, filePath, }; imgs.push(param); } } that.setData({ imgs: imgs, }); },});
上传图片:
uploadImgs(list) { const that = this; const imgList = []; list.forEach((item) => { wx.cloud.uploadFile({ cloudPath: `uploadImgs/${item.cloudPath}`, // 存入uploadImgs文件夹中 filePath: item.filePath, // 文件门路 }).then((res) => { if(res.errMsg === "cloud.uploadFile:ok") { imgList.push(res.fileID) } that.setData({ imgList, }) if(that.data.imgList.length === that.data.imgs.length) { that.add() } }) .catch((error) => { console.log(error); }); });},
最终把表单数据和图片列表数据到存入数据库汇合中。
add() { const that = this; wx.cloud.callFunction({ name: 'addGoods', data: { categoryId: that.data.categoryId, id: that.data.id, goodsName: that.data.goodsName, newPrice: that.data.newPrice, oldPrice: that.data.oldPrice, isHot: that.data.isHot, imgs: that.data.imgList } }).then()},
商品新增的云函数:
const cloud = require('wx-server-sdk')cloud.init()const db = cloud.database()const _ = db.commandexports.main = async (event, context) => { const goodsName = event.goodsName; const categoryId = event.categoryId; const id = event.id; const newPrice = event.newPrice; const oldPrice = event.oldPrice; const isHot = event.isHot; const imgs = event.imgs; db.collection("goods").doc(categoryId).update({ data: { list: _.push({ id, goodsName, newPrice, oldPrice, isHot, imgs }) } }) return { categoryId, id, goodsName, newPrice, oldPrice, isHot, imgs }}
喜爱列表页
最轻松的一个页面,读取本地缓存展现数据。这里还用到了WeUI的mp-slideview组件,批改这个组件的款式还是挺麻烦,高度款式没改胜利,多少存在点瑕疵。
个人信息页
这个页面曾经纯属和小程序宗旨性能无关了,我就是无聊写着玩凑凑页面的。想写些什么都能够自由发挥,轻易增加什么性能都能够,这里我就不介绍我轻易写的货色了。
至此,该篇历经四天的文章终于完结(次要是周末玩了两天),目前注释字数4500+......
我废话可真多呀。
这个小程序会持续保护,有任何不明确的中央分割我哦~