1. 添加收货地址按钮
1.1 页面结构与样式
- 页面结构:
<view class="cart">
<!-- 添加收货地址按钮 plain 代表背景透明-->
<view class="address_btn">
<button type="warn" plain bindtap="addAddressHandle">
添加收货地址
</button>
</view>
</view>
- 页面样式:
.cart {
.address_btn {
padding: 20rpx;
button {
color: var(--themeColor);
width: 60%;
}
}
}
1.2 处理添加收货地址事件
/**
* 处理添加收获地址事件
*/
addAddressHandle() {
wx.chooseAddress({
success: (result) => {
console.log(result);
},
});
},
- 点击添加收货地址按钮时如果我们没有点击确定,而是点击取消。这时会出现问题:之后再次点击添加收货地址按钮的时候就打不开选择地址的界面了。
1.3 权限演示
- 用户获取对小程序所授予获取地址的权限状态
scope
:
假设用户点击 获取地址的提示框的确定按钮
authSetting{scope.address 的值是 true}
。
假设用户点击获取地址的提示框的取消按钮scope 的值是 false
。
假设用户没有调用过选择地址的api
scope 的值是 undefined
- 查看权限信息:
wx.getSetting
:
wx.getSetting({
success: (result) => {
console.log(result);
},
});
- 解决点击了获取选择地址对话框取消按钮后无法再调起的问题:
addAddressHandle() {
// 正确获取收货地址的流程
wx.getSetting({
success: (result) => {
// 遇到这种比较特殊的属性名称的时候需要使用 [] 进行获取
const scopeAddress = result.authSetting["scope.address"]
if (scopeAddress === true || scopeAddress === undefined) {
// 表示曾经用户授予于了获取地址的权限 可以直接调用选择收货地址
wx.chooseAddress({
success: (result1) => {
console.log(result1);
}
});
} else {
// 曾经用户取消了选择收货地址权限的获取 需要重新让用户为选择收货地址授权
wx.openSetting({
success: (result2) => {
console.log(result2);
// 重新选择收货地址
wx.chooseAddress({
success: (result3) => {
console.log(result3);
}
});
}
});
}
},
});
},
- 使用ES7的语法优化以上的操作:
/**
* 权限设置
*/
export const getSetting = () => {
return new Promise((resolve, reject) => {
wx.getSetting({
success: (result) => {
resolve(result);
},
fail: (error) => {
reject(error);
}
});
});
}
export const chooseAddress = () => {
return new Promise((resolve, reject) => {
wx.chooseAddress({
success: (result) => {
resolve(result);
},
fail: (error) => {
reject(error);
}
});
});
}
export const openSetting = () => {
return new Promise((resolve, reject) => {
wx.openSetting({
success: (result) => {
resolve(result);
},
fail: (error) => {
reject(error);
}
});
});
}
async addAddressHandle() {
// 正确获取收货地址的流程
// 使用ES7优化后的代码
try {
const setRes = await getSetting();
const scopeAddress = setRes.authSetting["scope.address"]
console.log(scopeAddress);
// 判断当前权限状态
if (scopeAddress === false) {
await openSetting();
}
// 调用获取收货地址的 api
const address = await chooseAddress();
// 将获取结果存入到缓存中
wx.setStorageSync("address", address);
} catch (err) {
console.log(err);
}
},
1.4 获取本地存储中的地址数据
- 编写页面结构 :
<view class="cart">
<!-- 添加收货地址按钮 plain 代表背景透明-->
<!-- address空对象的boolean类型也是true 需要使用其属性的有无进行判断 -->
<view class="address_btn" wx:if="{{!address.userName}}">
<button type="warn" plain bindtap="addAddressHandle">
添加收货地址
</button>
</view>
<view class="user_info_row" wx:else>
<view class="user_info">
<view class="user_name">{{address.userName}}</view>
<view class="user_address">{{address.all}}</view>
</view>
<view class="user_phone">{{address.telNumber}}</view>
</view>
</view>
- 编写页面样式:
.user_info_row {
display: flex;
padding: 20rpx;
.user_info {
flex:5;
}
.user_phone {
flex:3;
text-align: right;
}
}
- 首先在data中定义一个变量保存在缓存中获取到的地址信息,需要在
onShow
生命周期函数中进行获取设置数据。
/**
* 生命周期函数--监听页面显示
*/
onShow: function() {
const address = wx.getStorageSync("address");
this.setData({
address
});
},
2.将缓存中的购物车商品数据显示到页面上
- 回到了商品详情页面,第一次添加商品的时候手动添加了属性
num = 1 ;
checked = true;
- 在
onShow
中获取缓存中的购物车数组。
const cart = wx.getStorageSync("cart");
- 将购物车数据填充到
data
变量中。
3. 底部工具栏的功能
3.1 全选功能
在
onshow
中获取缓存中的购物车数组。根据购物车中的商品数量,所有的商品都被选中 checked=true 全部就被选中。
数组的
every()
方法的使用 : 会遍历会接受一个回调函数,那么每一个回调函数都会返回true,那么every()
方法的返回值为true
只要有一个回调函数返回false
那么久不再循环执行,直接返回false
。假如是一个空数组调用了every()
方法返回值就是true
。
// 获取缓存中的购物车数据
const cart = wx.getStorageSync("cart");
// 使用every函数遍历数组中的 checked 属性
const allChecked = cart.length ? cart.every(v => v.checked) : false;
3.2 计算总价格和总数量
都需要商品被选中我们才能拿来计算。
获取购物车数组。
遍历。
判断商品是否被选中。
总价格 += 商品单价 * 商品数量。
总数量 += 商品数量。
将计算后的价格和数量设置回data中。
3.3 复选框的选中与取消选中
- 绑定
change
事件,并传递当前的商品id
。
<checkbox-group bindchange="checkboxChangeHandle" data-id="{{item.goods_id}}">
获取到被修改的商品对象。
商品对象的选中状态取反。
// 1. 接收传递过来的 商品 id
const goods_id = e.currentTarget.dataset.id;
// 2. 获取缓存中的购物车数据
const { cart } = this.data; // 在data中解构出 cart
// 3. 查询该商品id对应的索引
const index = cart.findIndex(v => v.goods_id === goods_id);
// 4 根据索引修改该商品的选中状态
cart[index].checked = !cart[index].checked;
重新填充回
data
中和缓存中。重新计算全选。总价格 总数量。
将选中和取消选中、计算合计价格、合计数量 设置购物车到
data
和缓存中抽取为一个方法:
/**
*
* @param {抽取处理 合计价格 合计数量设置购物车到data和缓存中的操作} cart
*/
setCart(cart) {
// 使用every函数遍历数组中的 checked 属性
// const allChecked = cart.length ? cart.every(v => v.checked) : false;
let allChecked = true; // 事先将其设置为true 到后面循环的时候发现有false的时候再将其设置为 false
let totalNum = 0;
let totalPrice = 0;
cart.forEach(v => {
if (v.checked) {
totalNum += v.num;
totalPrice += v.goods_price * v.num;
} else {
allChecked = false;
}
});
// 再对其值进行把关
allChecked = cart.length != 0 ? allChecked : false;
this.setData({
cart,
allChecked,
totalNum,
totalPrice
});
// 重新将cart对象设置到缓存中
wx.setStorageSync("cart", cart);
},
3.4 反选
复选框绑定一个
change
事件。获取
data
中的选中状态allchecked
;直接取反
allchecked = !allchecked
;遍历购物车数组让里面商品选中状态跟随
allchecked
改变而改变。将购物车数组 和
allchecked
重新设置会data
中 和 缓存中。
3.5 商品数量的编辑功能
- "+" "-" 按钮绑定同一个点击事件区分的关键 自定义属性。
"+" "+1"
"-" "-1"
<!-- 根据传递不同的操作符判断执行不同的操作 data-opt -->
<view class="edit_btn" bindtap="editGoodsNum" data-id="{{item.goods_id}}" data-opt="{{-1}}">-</view>
<view class="edit_btn" bindtap="editGoodsNum" data-id="{{item.goods_id}}" data-opt="{{1}}">+</view>
传递被点击的商品
id
opt
操作参数。获取data中的购物车数组,来获取需要被修改的对象。
直接修改商品对象的数量
num
。把
cart
数组 重新设置会缓存中和data
中 。
/**
*
* @param {购物车视频编辑事件} e
*/
editGoodsNum(e) {
// 获取传递过来的商品id 和 按钮操作参数
let { id, opt } = e.currentTarget.dataset;
// 根据商品id在 cart数组中查找 对应的商品索引
let { cart } = this.data;
const index = cart.findIndex(v => v.goods_id === id);
// 根据index修改数组中的指定商品信息
cart[index].num += opt;
// 将修改后的购物车数组重新设置到缓存中和data中
this.setCart(cart);
},
3.6 删除商品
当购物车的数量某个商品数量为 1 的同时用户点击 "-" ,弹窗提示(
showModel
)询问用户是否需要删除。将弹窗的请求的组件封装到,promise中通过ES7的去Promise简化操作。
/**
* 简化模态框提示操作
*/
export const showModal = ({ content }) => {
return new Promise((resolve, reject) => {
wx.showModal({
title: '提示',
content: content,
/* 这里需要使用箭头函数的形式 */
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err);
}
});
})
}
- 编辑购物车商品代码:
/**
*
* @param {购物车商品编辑事件} e
*/
async editGoodsNum(e) {
// 获取传递过来的商品id 和 按钮操作参数
let { id, opt } = e.currentTarget.dataset;
// 根据商品id在 cart数组中查找 对应的商品索引
let { cart } = this.data;
const index = cart.findIndex(v => v.goods_id === id);
/**
* 如果当前商品的数量是 1 且用户的操作是进行减 1 操作
*/
if (cart[index].num === 1 && opt === -1) {
const res = await showModal({ content: "您确定要删除当前商品吗?" });
// 点击确定的时候
if (res.comfirm) {
cart.splice(index, 1);
this.setCart(cart);
}
} else {
// 根据index修改数组中的指定商品信息
cart[index].num += opt;
this.setCart(cart);
}
// 将修改后的购物车数组重新设置到缓存中和data中
this.setCart(cart);
},
3.7 结算按钮功能
判断有没有收货地址信息。
判断用户有没有选购商品。
经过以上验证即可跳转到支付页面进行支付。
/**
* 处理结算逻辑
*/
async handlePay() {
const { address, totalNum } = this.data;
if (!address.userName) {
await showToast({ title: "您还未填写自己的地址信息!" });
return;
}
if (totalNum == 0) {
await showToast({ title: "您还未选择商品!" });
return;
}
wx.navigateTo({
url: '/pages/pay/index'
});
},
- 其中的
showToast
进行了抽取,使用ES7的Promise操作简化了操作:
/**
* 简化页面提示
*/
export const showToast = ({ title }) => {
return new Promise((resolve, reject) => {
wx.showToast({
title: title,
icon: 'none',
mask: true,
success: (res) => {
resolve(res)
},
fail: (err) => {
reject(err);
}
});
})
}