微信小程式實現購物車功能
阿新 • • 發佈:2019-01-28
在我的GitHub上有校園二手交易微信小程式的原始碼,這裡麵包含了購物車的功能,GitHub地址:https://github.com/zhuyuzhu/Secondhand-goods-on-campus,該專案的pages資料夾下的shoppingCart資料夾就是購物車的程式碼。
購物車功能實現的邏輯:
(1)從伺服器拿到的物品資料data裡面,只有物品的資訊,我們需要給每個物品資料中加入一個是否選中的屬性
這樣當我們在點選選擇按鈕的時候,就可以選中該物品,當再次點選的時候,就可以取消選擇。
其中幾個主要的功能:
(1)物品請求資料,使用微信小程式request請求,POST方式得到伺服器傳來的物品資料。
每次請求要想後端傳入使用者id和物品id(物品id根據後端要求進行處理,我每次傳入請求到的物品中最後一個物品的id,後端會把這個id之後的5個值再傳給前端)才得到的物品資料,每一次請求要判斷還有沒有資料,有資料則請求成功,沒有資料就不請求。
(2)選中和取消選中單個物品
(3)選中或取消選中物品時,總價格要進行加減
每次觸發選擇事件,都會觸發計算總價的方法
(4)全選按鈕,實現物品的全選
當用戶通過單選選擇了所有物品時,“全選按鈕”會自動改變為選中樣式;當用戶通過“全選按鈕”選擇所有商品的時候,每個商品都應該是選中狀態。
(5)計算總價
任何一次觸發該函式,都會重新計算價格,將總價變為0,再進行選中項的價格累加,而不是在原總價上累加或減某一個商品的價格
wxml程式碼:
<!--pages/shoppingCart/shoppingCart.wxml--> <view class='box'> <view class='wrapper'> <view class="tab-content {{selectBook? 'select': 'noSelect'}}" bindtap='chooseBookCart'>書本</view> <view class="tab-content {{selectThing? 'select': 'noSelect'}}" bindtap='chooseThingCart'>物品</view> </view> </view> <!-- 書本 --> <view class="cart-box" wx:if="{{selectBook}}"> <!-- wx:for 渲染購物車列表 --> <view wx:for="{{carts}}" wx:key="{{carts}}" class='cart-goods'> <!-- wx:if 是否選擇顯示不同圖示 --> <view class='icon-wrapper' bindtap="selectList" data-index="{{index}}"> <icon wx:if="{{item.selected}}" class='cart-icon' type="success" color="red" /> <icon wx:else type="circle" class='cart-icon' /> </view> <view class='cart-img'> <image class="cart-thumb" src="{{item.picture}}"></image> <view class='cart-message'> <text class='name'>書名:{{item.bname}}</text> <text class='author'>作者:{{item.author}}</text> <text class='press'>出版社:{{item.press}}</text> <text class='price'>價格:¥{{item.bprice}}</text> </view> </view> <!-- 點選商品圖片可跳轉到商品詳情 --> <!-- 刪除按鈕 --> <text bindtap="deleteList" data-index="{{index}}" class='delete'> × </text> </view> <view wx:if="{{isMyCartShow}}" class='bottom'>沒有書本啦~_~</view> </view> <!-- 物品 --> <view class="cart-box" wx:if="{{selectThing}}"> <!-- wx:for 渲染購物車列表 --> <view wx:for="{{thingCarts}}" wx:key="{{thingCarts}}" class='cart-goods'> <!-- wx:if 是否選擇顯示不同圖示 --> <view class='icon-wrapper' bindtap="selectListThing" data-index="{{index}}"> <icon wx:if="{{item.selected}}" class='cart-icon' type="success" color="red" /> <icon wx:else type="circle" class='cart-icon' /> </view> <view class='cart-img'> <image class="cart-thumb" src="{{item.gpicture}}"></image> <view class='cart-message'> <text class="name">{{item.gname}}</text> <text class="author">校區:{{item.gcollege}}</text> <text class='author'>成色:{{item.gstatus}}</text> <text class='author'>釋出者:{{item.usersname}}</text> <text class='price'>¥{{item.gprice}}</text> </view> </view> <!-- 點選商品圖片可跳轉到商品詳情 --> <!-- 刪除按鈕 --> <text bindtap="deleteListThing" data-index="{{index}}" class='delete'> × </text> </view> <view wx:if="{{isThingCartShow}}" class='bottom'>沒有物品啦~_~</view> </view> <!-- 底部操作欄 --> <view class='cart-bottom'> <!-- wx:if 是否全選顯示不同圖示 --> <icon wx:if="{{selectAllStatus}}" class='cart-iconAll' type="success_circle" color="red" bindtap="selectAll" /> <icon wx:else type="circle" class='cart-iconAll' color="#ff7100" bindtap="selectAll" /> <text class='cart-allSelect' bindtap="selectAll">全選</text> <!-- 總價 --> <text class='cart-allPrice'>合計:</text> <text class='allPrice'>¥{{totalPrice}}</text> <button class='btn-red' bindtap='toBuy' form-type='submit'>去結算</button> </view>
wxss程式碼:
/* pages/shoppingCart/shoppingCart.wxss */
.wrapper {
position: fixed;
top: 0rpx;
display: flex;
width: 100%;
height: 50rpx;
justify-content: space-around;
background-color: #fff;
z-index: 9999;
}
.select {
text-align: center;
width: 50%;
background-color: green;
color: #fff;
}
.noSelect {
width: 50%;
text-align: center;
}
.cart-box {
margin-top: 50rpx;
margin-bottom: 100rpx;
}
.cart-goods {
display: flex;
flex-direction: row;
padding: 30rpx;
border-bottom: 3rpx solid #e6e6e6;
}
.icon-wrapper {
line-height: 260rpx;
}
.cart-icon {
display: inline-block;
margin: auto 10rpx;
margin-left: -10rpx;
}
.cart-img {
display: flex;
width: 580rpx;
height: 260rpx;
}
.cart-img image{
margin: auto 0rpx;
width: 165rpx;
height: 225rpx;
}
.cart-goods .cart-message {
width: 380rpx;
display: flex;
flex-direction: column;
margin: 0 20rpx;
justify-content: space-around;
}
.name{
font-weight: 600;
color: #4a4a4a;
font-size: 32rpx;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.author,
.press{
font-size: 28rpx;
color: #9e9e9e;
font-weight: 300;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.price {
font-size: 28rpx;
color: #f40;
font-weight: 300;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.delete {
position: absolute;
right: 40rpx;
margin-top: -10rpx;
}
.cart-bottom {
position: fixed;
width: 100%;
height: 100rpx;
background-color: white;
bottom: 0rpx;
}
.cart-allPrice {
float:left;
padding: 0.5rem;
font-weight: 100;
margin-left: 70rpx;
}
.allPrice {
float:left;
padding: 0.5rem;
font-weight: 100;
margin-left: -30rpx;
color: #f40;
}
.cart-allSelect {
float:left;
padding: 0.5rem;
margin-left: -23rpx;
font-weight: 100
}
.cart-iconAll {
float:left;
padding: 0.5rem;
margin-top: 7rpx;
}
.btn-red {
background-color: #f44336; /* 紅色 */
font-size: 40rpx;
}
button {
position: fixed;
right: 0;
color: white;
text-align: center;
display: inline-block;
font-size: 30rpx;
border-radius: 0rpx;
width: 30%;
height: 100rpx;
line-height: 100rpx;
}
.cart-list {
display: flex;
flex-direction: column;
}
.bottom {
color: #666;
text-align: center;
font-size: 30rpx;
}
微信js程式碼:
// pages/shoppingCart/shoppingCart.js
var app = getApp();
const orginalPrice = 0; //由於0.00在賦值時是0,用toFixed()取餘
Page({
/**
* 頁面的初始資料
*/
data: {
selectTab: true,
selectBook: true,
selectThing: false,
carts: [], // 購物車列表
hasList: false, // 列表是否有資料
totalPrice: orginalPrice.toFixed(2), // 總價,初始為0
selectAllStatus: false, // 全選狀態,預設全選
bookId: '',
isMyCartShow: false,
studentId: '',
myCartBookLength: '5',
bookPrice: 0,
thingId: '',
thingCarts: [], // 物品列表
isThingCartShow: false,
myCartThingLength: '5',
thingPrice: 0,
},
/**
* 生命週期函式--監聽頁面載入
*/
onLoad: function (options) {
},
/**
* 生命週期函式--監聽頁面初次渲染完成
*/
onReady: function () {
},
/**
* 生命週期函式--監聽頁面顯示
*/
onShow: function () {
var that = this;
var studentId = that.data.studentId;
var hasList = that.data.hasList;
try {
var value = wx.getStorageSync('studentIdSync')
if (value) {
console.log(value); //同步得到studentId的值
that.setData({
studentId: value
})
}
} catch (e) {
console.log(0);
}
this.getBookCartList()
},
/**
* 生命週期函式--監聽頁面隱藏
*/
onHide: function () {
},
/**
* 生命週期函式--監聽頁面解除安裝
*/
onUnload: function () {
},
/**
* 頁面相關事件處理函式--監聽使用者下拉動作
*/
onPullDownRefresh: function () {
// 動態設定導航條標題
wx.setNavigationBarTitle({
title: '購物車'
});
wx.showNavigationBarLoading(); //在標題欄中顯示載入圖示
setTimeout(function(){
wx.stopPullDownRefresh(); //停止載入
wx.hideNavigationBarLoading(); //隱藏載入icon
},2000)
},
/**
* 頁面上拉觸底事件的處理函式
*/
onReachBottom: function () {
if (this.data.selectBook){
this.getBookCartList()
}else {
this.getThingCartList()
}
},
getBookCartList(){
console.log(1);
var that = this;
var url = app.globalData.huanbaoBase + 'getbooksbystudentid.php'
var ismyCartShow = that.data.ismyCartShow;
var carts = that.data.carts;
var bookId = that.data.bookId;
var myCartBookLength = that.data.myCartBookLength;
var studentId = that.data.studentId;
console.log(bookId, myCartBookLength);
// if (myCartBookLength < 5) {
// that.setData({
// isMyCartShow: true
// })
// return
// }
wx.showToast({
title: '載入中',
icon: 'loading',
duration: 1000,
})
wx.request({
url,
method: 'POST',
header: { 'content-type': 'application/x-www-form-urlencoded ' },
data: { //此處設定,一定要與後臺一一對應,屬性名和屬性的先後位置。
studentId: studentId,
lastId: bookId,
},
success: res => {
var carts = that.data.carts || [];
var data = res.data.data;
console.log(data);
if(data === undefined) {
wx.hideToast()
that.setData({
isMyCartShow: true
})
return
}
that.setData({
myCartBookLength: data.length //每次獲取5組值
})
myCartBookLength = data.length;
that.setData({
bookId: res.data.data[myCartBookLength - 1].bookid
})
console.log(myCartBookLength);
data.forEach(item => {
let messege = {
selected: false,
...item
}
carts.push(messege); //實現購物車的最近新增的物品,展現在最前面
})
that.setData({
carts: carts ,
})
},
fail: err => {
console.log(err);
}
})
},
getThingCartList() {
console.log(1);
var that = this;
var url = app.globalData.huanbaoBase + 'getthingsbystudentid.php'
var isThingCartShow = that.data.isThingCartShow;
var thingCarts = that.data.thingCarts;
var thingId = that.data.thingId;
var myCartThingLength = that.data.myCartThingLength;
var studentId = that.data.studentId;
var selectBook = that.data.selectBook;
var selectThing = that.data.selectThing;
console.log(thingId, myCartThingLength);
// if (myCartThingLength < 5) {
// that.setData({
// isThingCartShow: true
// })
// return
// }
wx.showToast({
title: '載入中',
icon: 'loading',
duration: 1000,
})
wx.request({
url,
method: 'POST',
header: { 'content-type': 'application/x-www-form-urlencoded ' },
data: { //此處設定,一定要與後臺一一對應,屬性名和屬性的先後位置。
studentId: studentId,
lastId: thingId,
},
success: res => {
var thingCarts = that.data.thingCarts || [];
var data = res.data.data;
console.log(data);
if (data === undefined) {
wx.hideToast()
that.setData({
isThingCartShow: true
})
return
}
that.setData({
myCartThingLength: data.length //每次獲取5組值
})
myCartThingLength = data.length;
that.setData({
thingId: res.data.data[myCartThingLength - 1].goodid
})
console.log(myCartThingLength);
data.forEach(item => {
let messege = {
selected: false,
...item
}
thingCarts.push(messege); //實現購物車的最近新增的物品,展現在最前面
})
that.setData({
thingCarts: thingCarts,
})
},
fail: err => {
console.log(err);
}
})
},
/**
* 使用者點選右上角分享
*/
onShareAppMessage: function () {
},
//計量總價
getTotalPrice() {
let carts = this.data.carts; // 獲取購物車列表
let thingPrice = parseFloat(this.data.thingPrice);
let bookPrice = parseFloat(this.data.bookPrice);
let total = 0.00;
for (let i = 0; i < carts.length; i++) { // 迴圈列表得到每個資料
if (carts[i].selected) { // 判斷選中才會計算價格
total += parseFloat(carts[i].bprice); // 所有價格加起來
}
}
this.setData({
bookPrice: total.toFixed(2)
})
total += thingPrice;
this.setData({ // 最後賦值到data中渲染到頁面
carts: carts,
totalPrice: total.toFixed(2) //保留小數後面2兩位
});
},
//選擇事件
selectList(e) {
let that = this;
const index = e.currentTarget.dataset.index; // 獲取data- 傳進來的index
console.log(index);
let selectAllStatus = that.data.selectAllStatus; //是否已經全選
let str = true; //用str與每一項進行狀態判斷
let carts = that.data.carts; // 獲取購物車列表
const selected = carts[index].selected; // 獲取當前商品的選中狀態
carts[index].selected = !selected; // 改變狀態
that.setData({
carts: carts
});
that.getTotalPrice(); // 重新獲取總價
for (var i = 0; i < carts.length; i++) {
str = str && carts[i].selected; //用str與每一項進行狀態判斷
}
if (str === true) {
that.setData({
selectAllStatus: true
})
} else {
that.setData({
selectAllStatus: false
})
}
},
//全選事件
selectAll(e) {
var that = this;
let selectAllStatus = that.data.selectAllStatus; // 是否全選狀態
let carts = that.data.carts;
let thingCarts = that.data.thingCarts;
var selectThing = that.data.selectThing;
var selectBook = that.data.selectBook;
if(selectBook) {
selectAllStatus = !selectAllStatus;
for (let i = 0; i < carts.length; i++) {
carts[i].selected = selectAllStatus; // 改變所有商品狀態
}
that.setData({
selectAllStatus: selectAllStatus,
carts: carts
});
that.getTotalPrice(); // 重新獲取總價
if (carts.length === 0) { //當沒有物品時,不能再點“全選”
wx.showModal({
title: '提示',
content: '購物車空空如也~',
success: function (res) { //模糊層成功出來後
if (res.confirm) {
console.log('使用者點選確定')
that.setData({
selectAllStatus: false
})
} else {
console.log('使用者點選取消')
that.setData({
selectAllStatus: false
})
}
},
})
}
}else {
selectAllStatus = !selectAllStatus;
for (let i = 0; i < thingCarts.length; i++) {
thingCarts[i].selected = selectAllStatus; // 改變所有商品狀態
}
that.setData({
selectAllStatus: selectAllStatus,
thingCarts: thingCarts
});
that.getTotalPriceThing(); // 重新獲取總價
if (thingCarts.length === 0) { //當沒有物品時,不能再點“全選”
wx.showModal({
title: '提示',
content: '購物車空空如也~',
success: function (res) { //模糊層成功出來後
if (res.confirm) {
console.log('使用者點選確定')
that.setData({
selectAllStatus: false
})
} else {
console.log('使用者點選取消')
that.setData({
selectAllStatus: false
})
}
},
})
}
}
},
//刪除商品
deleteList(e) {
const index = e.currentTarget.dataset.index;
var selectAllStatus = this.data.selectAllStatus;
let carts = this.data.carts;
let totalPrice = this.data.totalPrice;
wx.showModal({
title: '提示',
content: '將此產品移除購物車?',
success: res=> {
if (res.confirm) {
console.log('使用者點選確定')
carts.splice(index, 1); // 刪除購物車列表裡這個商品
this.setData({
carts: carts
});
if (carts.length == 0) { // 如果購物車為空
this.setData({
hasList: false, // 修改標識為false,顯示購物車為空頁面
selectAllStatus: false,
totalPrice: orginalPrice.toFixed(2) //此時價格為0
});
} else { // 如果不為空
this.getTotalPrice(); // 重新計算總價格
}
} else if (res.cancel) {
console.log('使用者點選取消')
}
}
})
},
// 物品
//計量總價
getTotalPriceThing() {
let thingCarts = this.data.thingCarts; // 獲取購物車列表
let total = 0; //注意後臺返回的是字串數字。
let thingPrice = parseFloat(this.data.thingPrice);
let bookPrice = parseFloat(this.data.bookPrice);
for (let i = 0; i < thingCarts.length; i++) { // 迴圈列表得到每個資料
if (thingCarts[i].selected) { // 判斷選中才會計算價格
total += parseFloat(thingCarts[i].gprice); // 所有價格加起來
}
}
this.setData({
thingPrice: total
})
total += bookPrice;
this.setData({ // 最後賦值到data中渲染到頁面
thingCarts: thingCarts,
totalPrice: total.toFixed(2) //保留小數後面2兩位
});
},
//選擇事件
selectListThing(e) {
let that = this;
const index = e.currentTarget.dataset.index; // 獲取data- 傳進來的index
console.log(index);
let selectAllStatus = that.data.selectAllStatus; //是否已經全選
let str = true; //用str與每一項進行狀態判斷
let thingCarts = that.data.thingCarts; // 獲取購物車列表
const selected = thingCarts[index].selected; // 獲取當前商品的選中狀態
thingCarts[index].selected = !selected; // 改變狀態
that.setData({
thingCarts: thingCarts
});
that.getTotalPriceThing(); // 重新獲取總價
for (var i = 0; i < thingCarts.length; i++) {
str = str && thingCarts[i].selected; //用str與每一項進行狀態判斷
}
console.log(str);
if (str === true) {
that.setData({
selectAllStatus: true
})
} else {
that.setData({
selectAllStatus: false
})
}
},
//刪除商品
deleteListThing(e) {
const index = e.currentTarget.dataset.index;
var selectAllStatus = this.data.selectAllStatus
let thingCarts = this.data.thingCarts;
let totalPrice = this.data.totalPrice;
wx.showModal({
title: '提示',
content: '將此產品移除購物車?',
success: res=> {
if(res.confirm){
console.log("使用者點了確定")
thingCarts.splice(index, 1); // 刪除購物車列表裡這個商品
this.setData({
thingCarts: thingCarts
});
if (thingCarts.length == 0) { // 如果購物車為空
this.setData({
hasList: false, // 修改標識為false,顯示購物車為空頁面
selectAllStatus: false,
totalPrice: orginalPrice.toFixed(2) //此時價格為0
});
} else { // 如果不為空
this.getTotalPrice(); // 重新計算總價格
}
}else if(res.cancel) {
console.log("使用者點了取消")
}
}
})
},
chooseBookCart() {
var that = this;
var selectBook = that.data.selectBook;
var selectThing = that.data.selectThing;
let selectAllStatus = that.data.selectAllStatus; //是否已經全選
let str = true; //用str與每一項進行狀態判斷
let carts = that.data.carts;
for (var i = 0; i < carts.length; i++) {
str = str && carts[i].selected; //用str與每一項進行狀態判斷
}
console.log(str);
that.setData({
selectBook: true,
selectThing: false,
})
},
chooseThingCart() {
var that = this;
var selectThing = that.data.selectThing;
var selectBook = that.data.selectBook;
var selectAllStatus = that.data.selectAllStatus;
that.setData({
selectBook: false,
selectThing: true,
})
// 此時data中的資料改變,但是此時的屬性值還未改變
that.getThingCartList()
},
toBuy(){
var totalPrice = this.data.totalPrice;
var thingCarts = this.data.thingCarts;
var bookCarts = this.data.carts;
var bookId = this.data.bookId;
var bookCart = [], thingCart = [];
bookCarts.forEach(item=>{
if (item.selected){
bookCart.push(item);
}
})
thingCarts.forEach(item=>{
if (item.selected){
thingCart.push(item);
}
})
let shoppingCartList = {thingCart, bookCart};
console.log(bookCart);
if(totalPrice === '0.00'){
console.log(totalPrice);
}else {
console.log(shoppingCartList);
wx.navigateTo({
url: '../settlement/settlement?bookCart='+bookCart,
})
}
}
})
後端程式碼和資料庫有時間再寫吧。。。