微信小程式專案wx-store程式碼詳解
這篇文章會很長,非常長,特別長,無敵長。
真的是擠牙膏般的專案進度,差不多是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 }) }
因為之前有小夥伴諮詢過,如何雲開發中資料庫新建集合,這裡用gif簡單說明一下。
為啥要兩個gif呢,因為超過300幀的它不給上傳~
輪播告示。
和輪播圖一樣的,只是輪播方向不同,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+......
我廢話可真多呀。
這個小程式會繼續維護,有任何不明白的地方聯絡我哦~
關注我吧