小程式購物車功能(支援手動輸入數量)以及側邊欄和列表欄聯動的實現
阿新 • • 發佈:2018-12-10
小組剛完成一個小程式專案,第一版正式釋出了,過程中也遇到了很多問題,這裡記錄一下我負責的模組中的購物車功能的實現過程。後期再把其他小夥伴的模組也一併貼上來分析一下,自己也學習一下他們的獨門技能!效果圖如下:
在這裡,計數器、購物籃做成元件用於複用,由於左右聯動的功能在另一個模組也有用到,所以就把這個功能也做成了一個元件,傳入不通的資料即可,左右聯動的實現方法在之前一片部落格有寫到
這篇部落格主要講一下選擇商品的功能,以及支援手動輸入的功能實現
數量選擇器
結構上採用左、中、右結構,加減號分別繫結兩個事件,中間輸入框繫結獲取焦點、失去焦點和change事件,用於支援手動輸入數量
<view class="wrapper"> <view class="num-choose {{totalNum || change ? 'active': ''}}"> <view class="minus {{totalNum || change ? 'active': ''}}" catchtap="minusHandle" data-goodsId="{{goodsId}}"> <tty-icon type="control-reduce"></tty-icon> </view> <view class="task task-left"></view> <input class="num" wx:if="{{totalNum || change}}" type="number" maxlength="4" bindinput="changeNum" value="{{totalNum}}" bindfocus="focusNum" bindblur="blurNum" data-goodsId=" {{goodsId}}"></input> <view class="task task-right"></view> <view class="plus" catchtap="plusHandle" data-goodsId="{{goodsId}}"> <tty-icon type="control-community"></tty-icon> </view> </view> </view>
作為元件,事件必須傳導到最上層,在那裡對資料進行處理
methods: { plusHandle(e) { // 增加事件 let {totalNum, typeOneIndex, typeTwoIndex, goodsIndex, totalStock} = this.data let goodsId = e.currentTarget.dataset.goodsid; // let pageX = e.touches[0].pageX; // let pageY = e.touches[0].pageY; totalNum++; if (totalStock === 0) { wx.showToast({ title: '請增加庫存!', icon: 'none', duration: 1500 }) return } if (totalNum > totalStock) { // 超過庫存 wx.showToast({ title: '庫存不足,請增加庫存!', icon: 'none', duration: 1500 }) return } this.setData({ totalNum, change: false }); let myEventDetail = { goodsId: goodsId, // pageX: pageX, // pageY: pageY, totalNum: totalNum, typeOneIndex: typeOneIndex, typeTwoIndex: typeTwoIndex, goodsIndex: goodsIndex, action: 'plus' // 增加事件標記 }; // detail物件,提供給事件監聽函式 this.triggerEvent('StepperEvent', myEventDetail) // 觸發父級事件 }, focusNum(e) { // 手動輸入時獲取基礎資料 this.triggerEvent('StepperEvent', { action: 'getNum', num: Number(e.detail.value) }); }, blurNum(e) { // 失去焦點,改變狀態 this.setData({ change: false }); // 購物籃失去焦點,商品數為0則清空 let myEventDetail = {} let goodsId = e.currentTarget.dataset.goodsid; myEventDetail = { goodsId: goodsId, action: 'blur' }; this.triggerEvent('StepperEvent', myEventDetail) }, changeNum(e) { let num = Number(e.detail.value) let {typeOneIndex, typeTwoIndex, goodsIndex, totalStock} = this.data let goodsId = e.currentTarget.dataset.goodsid; let myEventDetail = {} let totalNum = 0; if (num > totalStock) { // 超過庫存 wx.showToast({ title: '庫存不足,請增加庫存!', icon: 'none', duration: 1500 }) this.setData({ totalNum: num, change: false }); totalNum = totalStock; } else { totalNum = num; } myEventDetail = { goodsId: goodsId, totalNum: totalNum, typeOneIndex: typeOneIndex, typeTwoIndex: typeTwoIndex, goodsIndex: goodsIndex, action: 'change' }; this.setData({ totalNum: totalNum, change: true }); this.triggerEvent('StepperEvent', myEventDetail) }, minusHandle(e) { let num = this.data.totalNum; let {typeOneIndex, typeTwoIndex, goodsIndex} = this.data let goodsId = e.currentTarget.dataset.goodsid; if (num <= 0) { return } num--; let myEventDetail = { goodsId: goodsId, totalNum: num, typeOneIndex: typeOneIndex, typeTwoIndex: typeTwoIndex, goodsIndex: goodsIndex, action: 'minus' }; this.setData({ totalNum: num, change: false }); this.triggerEvent('StepperEvent', myEventDetail); } }
stemper元件是linkPage(商品左右聯動)元件的子元件,需要在linkPage裡過渡一下
linkPage.wxml
<view class="stepper" wx:if="{{!management}}">
<tty-stepper size="small" goodsId="{{pes.goods_id}}" typeOneIndex="{{typeOneIndex}}"
typeTwoIndex="{{typeTwoIndex}}" goodsIndex="{{goodsIndex}}" totalStock="
{{pes.stock}}" totalNum="{{pes.count}}" bindStepperEvent="stepperEvent">
</tty-stepper>
</view>
linkPage.js
stepperEvent(e) {
let myEventDetail = e.detail;
if(myEventDetail.action === 'blur') return
this.triggerEvent('ContentEvent', myEventDetail)
}
購物籃和列表欄的觸發事件要有所區分
choose-goods.wxml
最後所有資料彙集到主頁面進行處理
choose-goods.js 根據事件標記區分是哪一類事件,進行不同的處理
/*商品列表新增事件*/
contentEvent(e) {
let {totalNum, action, typeOneIndex, typeTwoIndex, goodsIndex} = e.detail;
if (action === 'getNum' || action === 'blur') {
this.setData({ // 獲取總基數
basePageTotalNum: this.data.pageTotalNum - e.detail.num
});
return
}
if (action === 'overStock') {
Dialog({
message: '該商品庫存不夠啦~',
confirmButtonText: '我知道了',
selector: '#tty-dialog-msg'
}).then(() => {});
return
}
this.addGoods(totalNum, action, typeOneIndex, typeTwoIndex, goodsIndex);
},
/*新增商品*/
addGoods(totalNum, action, typeOneIndex, typeTwoIndex, goodsIndex) {
let {typeData, goodsData, pageTotalNum} = this.data;
let goods = typeData[typeOneIndex].goods_category_two[typeTwoIndex].goods[goodsIndex];
typeData[typeOneIndex].goods_category_two[typeTwoIndex].goods[goodsIndex].count = totalNum;
if (action === 'plus') {
pageTotalNum++; // 商品總數
} else if (action === 'minus') {
pageTotalNum--;
} else if (action === 'change') {
pageTotalNum = this.data.basePageTotalNum + totalNum;
}
if (pageTotalNum < 0) {
pageTotalNum = 0;
return
}
goods.count = totalNum;
goods.typeOneIndex = typeOneIndex;
goods.typeTwoIndex = typeTwoIndex;
goods.goodsIndex = goodsIndex;
if (totalNum === 1 && action === 'plus') { // 購物籃裡沒有,則新增
goodsData.unshift(goods);
} else {
if(goodsData.includes(goods)) { // 如果購物籃中已有商品,在原有基礎上加1
let index = goodsData.indexOf(goods)
totalNum === 0 ? goodsData.splice(index, 1) : goodsData[index].count = totalNum;
}else { // 如果購物籃中沒有,則新增(針對手動修改)
goodsData.unshift(goods);
}
}
this.setData({
goodsData,
typeData,
pageTotalNum,
basePageTotalNum: pageTotalNum - totalNum
});
this.calculateMoney(goodsData);
}
/*購物框新增事件*/
basketEvent(e) {
if (e.detail.action === 'getNum') {
this.setData({ // 獲取計算基數
basePageTotalNum: this.data.pageTotalNum - e.detail.num
});
return
}
let {
totalNum, // 商品選擇的數量
goodsId, // 修改商品時對應的商品id
action // 操作行為
} = e.detail;
let {
typeData, // 列表資料
goodsData, // 購物籃資料
pageTotalNum // 頁面商品總數
} = this.data;
if (action === 'plus') {
pageTotalNum++;
} else if (action === 'minus') {
pageTotalNum--;
} else if (action === 'change') {
pageTotalNum = this.data.basePageTotalNum + totalNum;
}
if (pageTotalNum < 0) {
pageTotalNum = 0;
}
for (let i = 0; i < goodsData.length; i++) {
if (goodsData[i].goods_id === goodsId) {
// 獲取索引,處理列表商品數量
let typeOneIndex = goodsData[i].typeOneIndex;
let typeTwoIndex = goodsData[i].typeTwoIndex;
let goodsIndex = goodsData[i].goodsIndex;
let count = 0;
if (action === 'plus') {
goodsData[i].count++;
count = goodsData[i].count
} else if (action === 'minus') {
goodsData[i].count--;
count = goodsData[i].count
if (goodsData[i].count <= 0) {
goodsData[i].count = 0;
goodsData.splice(i, 1);
}
} else if (action === 'change') {
if(totalNum <= 0) {
goodsData[i].count = 0;
}else {
goodsData[i].count = totalNum;
}
count = goodsData[i].count
// 失去焦點,數量為0,刪除
} else if (action === 'blur' && goodsData[i].count === 0) {
count = goodsData[i].count
goodsData.splice(i, 1);
}
typeData[typeOneIndex].goods_category_two[typeTwoIndex].goods[goodsIndex].count = count;
}
}
this.setData({
goodsData,
typeData,
pageTotalNum,
basePageTotalNum: pageTotalNum - totalNum
});
this.calculateMoney(goodsData);// 計算總金額
}
列表欄中新增商品時,購物籃中沒有商品,跟隨列表欄變化而變化,屬於正向計算,比較簡單,有則加1,無則新增
反過來,購物籃中修改資料時就麻煩些了,需要拿到對應的商品id,反向查詢列表欄中的商品,並做修改
由上面的效果圖可以知道,資料的格式是三層巢狀的陣列,這就導致資料的查詢比較麻煩,必須迴圈遍歷才能找到最底層的資料
"data": [{
goods_category_one_id: "221310651891449856",
goods_category_one_name: "農藥",
goods_category_two: [
{
goods_category_two_id: "221310651891449858",
goods_category_two_name: "殺蟲劑",
goods: [{
amount: 0,
base_unit_id: "221310649857212419",
base_unit_name: "桶",
count: 0,
goods_id: "258169085668364288",
goods_name: "聯苯·蟲蟎腈",
goods_spec: "",
price: 3.5,
stock: 24,
url: ""
}]
},
{
goods_category_two_id: "221310651891449859",
goods_category_two_name: "殺菌劑",
goods: [{
amount: 0,
base_unit_id: "221310649857212422",
base_unit_name: "克",
count: 0,
goods_id: "258168407638147072",
goods_name: "聯苯·蟲蟎腈",
goods_spec: "",
price: 3.5,
stock: 24,
url: ""
},
{
amount: 0,
base_unit_id: "221310649857212421",
base_unit_name: "克",
count: 0,
goods_id: "259282725129682944",
goods_name: "速克靈100g",
goods_spec: "",
price: 5.6,
stock: 0,
url: ""
},
{
amount: 0,
base_unit_id: "221310649857212420",
base_unit_name: "盒",
count: 0,
goods_id: "259285646445645824",
goods_name: "解決",
goods_spec: "",
price: 56,
stock: 12,
url: ""
}
]
}
]
}