乐趣区

关于微信小程序:微信小程序项目wxstore代码详解

这篇文章会很长,十分长,特地长,无敌长。

真的是挤牙膏般的我的项目进度,差不多是 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.command
exports.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+……

我废话可真多呀。

这个小程序会持续保护,有任何不明确的中央分割我哦~

退出移动版