(中篇)承接(上篇内容),接口文档和阿里图标库已在(上篇)给出,本文所粘贴代码或许存在不完整之处,完整代码请见(下篇)。
先书写轮播图结构,在goods_detail文件夹下的index.wxml内修改代码。然后index.wxss修改样式
<!--pages/goods_detail/index.wxml-->
<view class="detail_swiper">
<!-- 轮播图内容 -->
<swiper autoplay="true" circular="true" indicator-dots="true">
<swiper-item wx:for="{{goodsObj.data.message.pics}}" wx:key="pics_id">
<image mode="widthFix" src="{{item.pics_mid}}"></image>
</swiper-item>
</swiper>
</view>
/* pages/goods_detail/index.wxss */
.detail_swiper swiper{
height: 70vw;
text-align: center;
}
.detail_swiper image{
width: 60%;
}
其中使用了富文本标签rich-text
,要渲染的数据都在接口文档中请求接口返回的数据里,我们使用了goodsObj把返回的数据进行了存储。
<!--pages/goods_detail/index.wxml-->
<view class="detail_swiper">
<!-- 轮播图内容 -->
<swiper autoplay="true" circular="true" indicator-dots="true">
<swiper-item wx:for="{{goodsObj.data.message.pics}}" wx:key="pics_id">
<image mode="widthFix" src="{{item.pics_mid}}"></image>
</swiper-item>
</swiper>
</view>
<!-- 商品内容文字 -->
<!-- 商品价格 -->
<view class="goods_price">¥{{goodsObj.data.message.goods_price}}</view>
<view class="goods_name_row">
<!-- 商品名字 -->
<view class="goods_name">{{goodsObj.data.message.goods_name}}</view>
<!-- 收藏商品 -->
<view class="goods_collect">
<!-- 这里的收藏图标是引入了阿里图标库的 -->
<text class="iconfont icon-shoucang"></text>
<view class="collect_text">收藏</view>
</view>
</view>
<!-- 图文详情 -->
<view class="goods_info">
<view class="goods_info_title">图文详情</view>
<view class="goods_info_content">
<!-- 富文本渲染 -->
<rich-text nodes="{{goodsObj.data.message.goods_introduce}}"></rich-text>
</view>
</view>
/* pages/goods_detail/index.wxss */
.detail_swiper swiper {
height: 70vw;
text-align: center;
}
.detail_swiper image {
width: 60%;
}
.goods_price {
padding: 15rpx;
font-size: 32rpx;
font-weight: 600;
color: var(--themColor);
}
.goods_name_row {
display: flex;
border-top: 5rpx solid #dedede;
border-bottom: 5rpx solid #dedede;
padding: 10rpx 0;
}
.goods_name_row .goods_collect {
flex: 1;
display: flex;
/* 主轴方向变成上下(纵轴)的方向 */
flex-direction: column;
justify-content: center;
align-items: center;
border-left: 1rpx solid #000;
}
.goods_name_row .goods_name {
flex: 5;
color: #000;
font-size: 28rpx;
padding: 0 10rpx;
/* 当文字超出很多时,使用省略号来代替多出的文字进显示 */
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.goods_info {}
.goods_info_title {
font-size: 32rpx;
color: var(--themColor);
font-weight: 600;
padding: 20rpx;
}
.goods_info_content {}
当观察goodsObj内的数据,我们发现里边存储的有些数据并没有用到,这就会占用小程序性能,所以我们需要对goodsObj的赋值函数进行处理,并且部分iphone手机 不识别webp图片格式,因此返回的数据中是webp格式的图片在苹果手机上可能渲染失败。解决上述两个问题:
wx:for
遍历数据的格式replace
函数// pages/goods_detail/index.js
//引入用来发送请求的方法,优化后的
import {
request
} from "../../request/index.js"
Page({
/**
* 页面的初始数据
*/
data: {
//请求返回的数据是以对象形式
goodsObj: {}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//拿到跳转页面时传递过来的商品id
const {
goods_id
} = options;
this.getGoodsDetail(goods_id);
},
/**
* 获取商品详情数据
*/
async getGoodsDetail(goods_id) {
const goodsObj = await request({
url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/detail",
data: {
goods_id
}
});
this.setData({
// 优化存储数据,只赋值存储小程序用到的数据
goodsObj:{
goods_name:goodsObj.data.message.goods_name,
goods_price:goodsObj.data.message.goods_price,
// iphone部分手机不支持webp格式
// 后台修改
// 或者自己临时修改 使用replace函数 其中\.webp是找到所有.webp的文件,g表示全选,.jpg表示全部替换为.jpg格式。
goods_introduce:goodsObj.data.message.goods_introduce.replace(/\.webp/g,'.jpg'),
pics:goodsObj.data.message.pics
}
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
<!--pages/goods_detail/index.wxml-->
<view class="detail_swiper">
<!-- 轮播图内容 -->
<swiper autoplay="true" circular="true" indicator-dots="true">
<swiper-item wx:for="{{goodsObj.pics}}" wx:key="pics_id">
<image mode="widthFix" src="{{item.pics_mid}}"></image>
</swiper-item>
</swiper>
</view>
<!-- 商品内容文字 -->
<!-- 商品价格 -->
<view class="goods_price">¥{{goodsObj.goods_price}}</view>
<view class="goods_name_row">
<!-- 商品名字 -->
<view class="goods_name">{{goodsObj.goods_name}}</view>
<!-- 收藏商品 -->
<view class="goods_collect">
<!-- 这里的收藏图标是引入了阿里图标库的 -->
<text class="iconfont icon-shoucang"></text>
<view class="collect_text">收藏</view>
</view>
</view>
<!-- 图文详情 -->
<view class="goods_info">
<view class="goods_info_title">图文详情</view>
<view class="goods_info_content">
<!-- 富文本渲染 -->
<rich-text nodes="{{goodsObj.goods_introduce}}"></rich-text>
</view>
</view>
点击商品详情处的轮播图后,会进行放大预览。步骤如下
previewImage
// pages/goods_detail/index.js
//引入用来发送请求的方法,优化后的
import {
request
} from "../../request/index.js"
Page({
/**
* 页面的初始数据
*/
data: {
//请求返回的数据是以对象形式
goodsObj: {}
},
//定义要预览的大图信息数组全局变量
goodsInfo: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//拿到跳转页面时传递过来的商品id
const {
goods_id
} = options;
this.getGoodsDetail(goods_id);
},
/**
* 获取商品详情数据
*/
async getGoodsDetail(goods_id) {
const goodsObj = await request({
url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/detail",
data: {
goods_id
}
});
//请求成功之后给之前定义的预览大图数组赋值
this.goodsInfo=goodsObj.data.message;
this.setData({
// 优化存储数据,只赋值存储小程序用到的数据
goodsObj: {
goods_name: goodsObj.data.message.goods_name,
goods_price: goodsObj.data.message.goods_price,
// iphone部分手机不支持webp格式
// 后台修改
// 或者自己临时修改 使用replace函数 其中\.webp是找到所有.webp的文件,g表示全选,.jpg表示全部替换为.jpg格式。
goods_introduce: goodsObj.data.message.goods_introduce.replace(/\.webp/g, '.jpg'),
pics: goodsObj.data.message.pics
},
})
},
/**
* 点击轮播图预览大图事件
*/
handlePrevewImage(e) {
console.log('预览');
// 先构建要预览的图片数组
const urls=this.goodsInfo.pics.map(v=>v.pics_mid)
// 接受传递过来的图片url
const current = e.currentTarget.dataset.url
wx.previewImage({
current: current,
urls: urls
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
<!--pages/goods_detail/index.wxml-->
<view class="detail_swiper">
<!-- 轮播图内容,bindtap绑定一个预览大图事件 -->
<swiper autoplay="true" circular="true" indicator-dots="true" bindtap="handlePrevewImage" data-url="{{item.pics_mid}}">
<swiper-item wx:for="{{goodsObj.pics}}" wx:key="pics_id">
<image mode="widthFix" src="{{item.pics_mid}}"></image>
</swiper-item>
</swiper>
</view>
<!-- 商品内容文字 -->
<!-- 商品价格 -->
<view class="goods_price">¥{{goodsObj.goods_price}}</view>
<view class="goods_name_row">
<!-- 商品名字 -->
<view class="goods_name">{{goodsObj.goods_name}}</view>
<!-- 收藏商品 -->
<view class="goods_collect">
<!-- 这里的收藏图标是引入了阿里图标库的 -->
<text class="iconfont icon-shoucang"></text>
<view class="collect_text">收藏</view>
</view>
</view>
<!-- 图文详情 -->
<view class="goods_info">
<view class="goods_info_title">图文详情</view>
<view class="goods_info_content">
<!-- 富文本渲染 -->
<rich-text nodes="{{goodsObj.goods_introduce}}"></rich-text>
</view>
</view>
底部导航栏的客服、分享等功能,点击后均可响应,依赖于小程序的开放能力,可以在官网文档查找相关说明。同时将按钮巧妙的隐藏在了这两个标签底层,实际上我们点击客服和分析时,点击的是隐藏的按钮。我们还实现了点击购物车图标跳转到cart购物车页面。
注意:navigator是一个类似于超链接标签,默认是以navigate方式跳转,但是这种方式不能跳转tabbar(导航栏页面),所以我们使用open-type="switchTab"
进行跳转。
<!--pages/goods_detail/index.wxml-->
<view class="detail_swiper">
<!-- 轮播图内容,bindtap绑定一个预览大图事件 -->
<swiper autoplay="true" circular="true" indicator-dots="true" bindtap="handlePrevewImage"
data-url="{{item.pics_mid}}">
<swiper-item wx:for="{{goodsObj.pics}}" wx:key="pics_id">
<image mode="widthFix" src="{{item.pics_mid}}"></image>
</swiper-item>
</swiper>
</view>
<!-- 商品内容文字 -->
<!-- 商品价格 -->
<view class="goods_price">¥{{goodsObj.goods_price}}</view>
<view class="goods_name_row">
<!-- 商品名字 -->
<view class="goods_name">{{goodsObj.goods_name}}</view>
<!-- 收藏商品 -->
<view class="goods_collect">
<!-- 这里的收藏图标是引入了阿里图标库的 -->
<text class="iconfont icon-shoucang"></text>
<view class="collect_text">收藏</view>
</view>
</view>
<!-- 图文详情 -->
<view class="goods_info">
<view class="goods_info_title">图文详情</view>
<view class="goods_info_content">
<!-- 富文本渲染 -->
<rich-text nodes="{{goodsObj.goods_introduce}}"></rich-text>
</view>
</view>
<!-- 底部导航栏 -->
<view class="btm_tool">
<!-- 客服 -->
<view class="tool_item">
<view class="iconfont icon-kefu"></view>
<view>客服</view>
<!-- 增加联系客服功能 ,隐藏在客服的下一层,透明度为0,设置其高和宽与客服部分一致-->
<button open-type="contact"></button>
</view>
<!-- 分享 -->
<view class="tool_item">
<view class="iconfont icon-fenxiang"></view>
<view>分享</view>
<button open-type="share"></button>
</view>
<!-- 购物车 -->
<!-- switchTab允许跳转tabBar(导航栏)页面 -->
<navigator open-type="switchTab" url="/pages/cart/index" class="tool_item">
<view class="tool_item">
<view class="iconfont icon-gouwuche"></view>
<view>购物车</view>
</view>
</navigator>
<!-- 加入购物车 -->
<view class="tool_item btn_cart">
<view class="">加入购物车</view>
</view>
<!-- 立即购买 -->
<view class="tool_item btn_buy">
<view>立即购买</view>
</view>
</view>
/* pages/goods_detail/index.wxss */
/* 防止增添的固定导航栏,在页面滑至最底部时造成遮挡部分页面内容,
这里设置页面的底部扩充出90rpx,给固定导航栏 */
page{
padding-bottom: 90rpx;
}
.detail_swiper swiper {
height: 70vw;
text-align: center;
}
.detail_swiper image {
width: 60%;
}
.goods_price {
padding: 15rpx;
font-size: 32rpx;
font-weight: 600;
color: var(--themColor);
}
.goods_name_row {
display: flex;
border-top: 5rpx solid #dedede;
border-bottom: 5rpx solid #dedede;
padding: 10rpx 0;
}
.goods_name_row .goods_collect {
flex: 1;
display: flex;
/* 主轴方向变成上下(纵轴)的方向 */
flex-direction: column;
justify-content: center;
align-items: center;
border-left: 1rpx solid #000;
}
.goods_name_row .goods_name {
flex: 5;
color: #000;
font-size: 28rpx;
padding: 0 10rpx;
/* 当文字超出很多时,使用省略号来代替多出的文字进显示 */
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.goods_info_title {
font-size: 32rpx;
color: var(--themColor);
font-weight: 600;
padding: 20rpx;
}
.btm_tool {
/* position加固定定位,固定在页面中 */
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 90rpx;
background-color: #fff;
display: flex;
}
.btm_tool .tool_item {
border-top: 1rpx solid #ccc;
flex:1;
display: flex;
/* 改变主轴方向为上下方向 */
flex-direction: column;
/* 垂直和水平居中 */
justify-content: center;
text-align: center;
font-size: 24rpx;
/* 父样式相对定位 */
position: relative;
}
.btm_tool .tool_item button{
/* 子样式绝对定位 */
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
/* 透明度 */
opacity: 0;
}
.btn_cart {
flex: 2;
background-color: #ffa500;
color: #fff;
font-size: 28rpx;
font-weight: 600;
}
.btn_buy {
flex: 2;
background-color: var(--themColor);
color: #fff;
font-size: 28rpx;
font-weight: 600;
}
在商品详情页,查看完某一商品后,点击加入购物车,实现加入功能。实现步骤如下
<!--pages/goods_detail/index.wxml-->
<view class="detail_swiper">
<!-- 轮播图内容,bindtap绑定一个预览大图事件 -->
<swiper autoplay="true" circular="true" indicator-dots="true" bindtap="handlePrevewImage"
data-url="{{item.pics_mid}}">
<swiper-item wx:for="{{goodsObj.pics}}" wx:key="pics_id">
<image mode="widthFix" src="{{item.pics_mid}}"></image>
</swiper-item>
</swiper>
</view>
<!-- 商品内容文字 -->
<!-- 商品价格 -->
<view class="goods_price">¥{{goodsObj.goods_price}}</view>
<view class="goods_name_row">
<!-- 商品名字 -->
<view class="goods_name">{{goodsObj.goods_name}}</view>
<!-- 收藏商品 -->
<view class="goods_collect">
<!-- 这里的收藏图标是引入了阿里图标库的 -->
<text class="iconfont icon-shoucang"></text>
<view class="collect_text">收藏</view>
</view>
</view>
<!-- 图文详情 -->
<view class="goods_info">
<view class="goods_info_title">图文详情</view>
<view class="goods_info_content">
<!-- 富文本渲染 -->
<rich-text nodes="{{goodsObj.goods_introduce}}"></rich-text>
</view>
</view>
<!-- 底部导航栏 -->
<view class="btm_tool">
<!-- 客服 -->
<view class="tool_item">
<view class="iconfont icon-kefu"></view>
<view>客服</view>
<!-- 增加联系客服功能 ,隐藏在客服的下一层,透明度为0,设置其高和宽与客服部分一致-->
<button open-type="contact"></button>
</view>
<!-- 分享 -->
<view class="tool_item">
<view class="iconfont icon-fenxiang"></view>
<view>分享</view>
<button open-type="share"></button>
</view>
<!-- 购物车 -->
<!-- switchTab允许跳转tabBar(导航栏)页面 -->
<navigator open-type="switchTab" url="/pages/cart/index" class="tool_item">
<view class="tool_item">
<view class="iconfont icon-gouwuche"></view>
<view>购物车</view>
</view>
</navigator>
<!-- 加入购物车 -->
<!-- 增加点击事件,添加商品响应 -->
<view class="tool_item btn_cart" bindtap="handleCartAdd">
<view>加入购物车</view>
</view>
<!-- 立即购买 -->
<view class="tool_item btn_buy">
<view>立即购买</view>
</view>
</view>
// pages/goods_detail/index.js
//引入用来发送请求的方法,优化后的
import {
request
} from "../../request/index.js"
Page({
/**
* 页面的初始数据
*/
data: {
//请求返回的数据是以对象形式
goodsObj: {}
},
//定义要预览的大图信息数组全局变量
goodsInfo: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//拿到跳转页面时传递过来的商品id
const {
goods_id
} = options;
this.getGoodsDetail(goods_id);
},
/**
* 获取商品详情数据
*/
async getGoodsDetail(goods_id) {
const goodsObj = await request({
url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/detail",
data: {
goods_id
}
});
//请求成功之后给之前定义的预览大图数组赋值
this.goodsInfo = goodsObj.data.message;
this.setData({
// 优化存储数据,只赋值存储小程序用到的数据
goodsObj: {
goods_name: goodsObj.data.message.goods_name,
goods_price: goodsObj.data.message.goods_price,
// iphone部分手机不支持webp格式
// 后台修改
// 或者自己临时修改 使用replace函数 其中\.webp是找到所有.webp的文件,g表示全选,.jpg表示全部替换为.jpg格式。
goods_introduce: goodsObj.data.message.goods_introduce.replace(/\.webp/g, '.jpg'),
pics: goodsObj.data.message.pics
},
})
},
/**
* 点击轮播图预览大图事件
*/
handlePrevewImage(e) {
console.log('预览');
// 先构建要预览的图片数组
const urls = this.goodsInfo.pics.map(v => v.pics_mid)
// 接受传递过来的图片url
const current = e.currentTarget.dataset.url
wx.previewImage({
current: current,
urls: urls
})
},
/**
* 用户商品加入购物车事件
*/
handleCartAdd(e) {
//获取缓存的商品数据,并由字符串格式转为数组格式
let cart=wx.getStorageSync('cart')||[];
// 判定商品是否已存在购物车数组中
let index=cart.findIndex(v=>v.goods_id===this.goodsInfo.goods_id);
if(index===-1){
//不存在,第一次添加
this.goodsInfo.num=1;
cart.push(this.goodsInfo);
}else{
//存在
cart[index].num++;
}
//购物车数组更新到缓存中
wx.setStorageSync("cart",cart);
//弹窗提示
wx.showToast({
title: '添加成功',
icon:'success',
mask:'true'
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
点击加入购物车后,商品会被加入到购物车中,随后点击购物车,进入购物车内容页面。该页面对应cart文件夹,首先是修改页面标题,在cart文件夹下的index.json文件修改代码
{
"usingComponents": {},
"navigationBarTitleText": "购物车"
}
随后开始书写相关页面结构,在index.wxml中修改代码。
<!--pages/cart/index.wxml-->
<!-- 收货地址容器 -->
<view class="receive_address">
<!-- 收货地址按钮 -->
<!-- wx:if判断如果地址里边的用户名是否存在,不存在时显示 -->
<view class="address" wx:if="{{!address.userName}}">
<!-- plain表示按钮是否镂空,背景色透明 -->
<!-- 绑定点击事件,获取收货地址 -->
<button type="primary" plain="true" bindtap="handleChooseAddress">增添收货地址</button>
</view>
<!-- 当收货地址用户名存在,即有收货地址时 -->
<view wx:else class="user_info_row">
<view class="user_info">
<view> {{address.userName}}</view>
<view>{{address.all}}</view>
</view>
<view class="user_phone">
{{address.telNumber}}
</view>
</view>
</view>
<!-- 购物车具体内容 -->
<view class="cart_content">
<view class="cart_title">购物车</view>
<view class="cart_main">
<view class="cart_item">
<!-- 复选框结构 -->
<view class="cart_checkbox">
<checkbox-group bindchange="">
<checkbox></checkbox>
</checkbox-group>
</view>
<!-- 商品图片 -->
<navigator class="cart_image">
<image mode="widthFix"
src="http://image2.suning.cn/uimg/b2c/newcatentries/0000000000-000000000178667792_2_800x800.jpg">
</image>
</navigator>
<!-- 商品信息 -->
<view class="cart_info">
<view class="goods_name">TCL 65Q960C 65英寸 哈曼卡顿 人工智能 金属超薄 64位34核 4K+HDR 原色量子点 曲面电视(灰色)</view>
<view class="goods_price_wrap">
<view class="goods_price">¥999</view>
<view class="cart_num_tool">
<view class="num_edit">-</view>
<view class="goods_nums">1</view>
<view class="num_edit">+</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 底部导航栏 -->
<view class="footer_tool">
<!-- 全选 -->
<view class="all_check_wrap">
<checkbox-group>
<checkbox>全选</checkbox>
</checkbox-group>
</view>
<!-- 总价格 -->
<view class="total_price_wrap">
<view class="total_price">
合计:<text class="total_price_number">¥999</text>
</view>
<view>包含运费</view>
</view>
<!-- 结算 -->
<view class="order_pay_wrap">结算(1)</view>
</view>
样式文件
/* pages/cart/index.wxss */
page{
padding-bottom: 90rpx;
}
.address {
padding: 20rpx;
}
.address button {
width: 60%;
}
.user_info_row {
display: flex;
padding: 20rpx;
}
.user_info {
flex: 5;
}
.user_phone {
flex: 2;
text-align: center;
justify-content: center;
}
.cart_title {
padding: 20rpx;
font-size: 36rpx;
color: var(--themColor);
border-top: 1rpx solid currentColor;
border-bottom: 1rpx solid currentColor;
}
.cart_item {
display: flex;
}
.cart_item .cart_checkbox {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.cart_item .cart_checkbox checkbox-group {
display: flex;
}
.cart_item .cart_image {
flex: 2;
display: flex;
justify-content: center;
align-items: center;
}
.cart_image image {
width: 80%;
}
.cart_info {
flex: 4;
display: flex;
justify-content: space-around;
flex-direction: column;
}
.cart_info .goods_name {
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
color: #666;
}
.cart_info .goods_price_wrap {
display: flex;
justify-content: space-between;
}
.goods_price {
color: var(--themColor);
font-size: 34rpx;
}
.cart_num_tool {
display: flex;
}
.num_edit {
width: 55rpx;
height: 55rpx;
display: flex;
justify-content: center;
align-items: center;
border: 1rpx solid #ccc;
}
.goods_nums {
width: 55rpx;
height: 55rpx;
display: flex;
justify-content: center;
align-items: center;
}
.footer_tool{
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 90rpx;
background-color: #fff;
display: flex;
border-top: 1rpx solid #ccc;
}
.all_check_wrap{
flex: 2;
display: flex;
justify-content: center;
align-items: center;
}
.total_price_wrap{
flex: 4;
padding-right: 15rpx;
/* 文字右对齐 */
text-align: right;
}
.total_price_number{
color: var(--themColor);
font-size: 34rpx;
font-weight: 600;
}
.order_pay_wrap{
flex: 2;
background-color: var(--themColor);
color: #fff;
font-size: 32rpx;
font-weight: 600;
display: flex;
justify-content: center;
align-items: center;
}
在index.js文件中的onShow函数,要在里边获取缓存中的购物车数组,然后把购物车数组更新到data中去。
// pages/cart/index.js
Page({
// 点击获取收货地址事件
// 1.绑定点击事件
// 2.调用小程序内API,"wx.chooseAddress",获取用户的收货地址
// 购物车页面加载完毕
// 1.获取本地存储中的收货地址数据
// 2.如果有存储,就把数据 设置给data中的一个变量
handleChooseAddress(e) {
wx.chooseAddress({
success: (result) => {
// 把获取的地址存入本地缓存中,在存储之前先进行一个地址拼接
result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo;
console.log(result);
wx.setStorageSync('address', result)
},
});
},
/**
* 页面的初始数据
*/
data: {
address: {},
//声明一个变量,购物车数组
cart:[]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
//获取缓存中的购物车数据
const cart=wx.getStorageSync('cart')
//获取缓存中的收货地址信息
const address = wx.getStorageSync('address');
//给data赋值
this.setData({
address,
cart:cart
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
<!--pages/cart/index.wxml-->
<!-- 收货地址容器 -->
<view class="receive_address">
<!-- 收货地址按钮 -->
<!-- wx:if判断如果地址里边的用户名是否存在,不存在时显示 -->
<view class="address" wx:if="{{!address.userName}}">
<!-- plain表示按钮是否镂空,背景色透明 -->
<!-- 绑定点击事件,获取收货地址 -->
<button type="primary" plain="true" bindtap="handleChooseAddress">增添收货地址</button>
</view>
<!-- 当收货地址用户名存在,即有收货地址时 -->
<view wx:else class="user_info_row">
<view class="user_info">
<view> {{address.userName}}</view>
<view>{{address.all}}</view>
</view>
<view class="user_phone">
{{address.telNumber}}
</view>
</view>
</view>
<!-- 购物车具体内容 -->
<view class="cart_content">
<view class="cart_title">购物车</view>
<view class="cart_main">
<view class="cart_item" wx:for="{{cart}}" wx:key="goods_id">
<!-- 复选框结构 -->
<view class="cart_checkbox">
<checkbox-group bindchange="">
<checkbox></checkbox>
</checkbox-group>
</view>
<!-- 商品图片 -->
<navigator class="cart_image">
<image mode="widthFix"
src="{{item.goods_small_logo}}">
</image>
</navigator>
<!-- 商品信息 -->
<view class="cart_info">
<view class="goods_name">{{item.goods_name}}</view>
<view class="goods_price_wrap">
<view class="goods_price">{{item.goods_price}}</view>
<view class="cart_num_tool">
<view class="num_edit">-</view>
<view class="goods_nums">{{item.num}}</view>
<view class="num_edit">+</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 底部导航栏 -->
<view class="footer_tool">
<!-- 全选 -->
<view class="all_check_wrap">
<checkbox-group>
<checkbox>全选</checkbox>
</checkbox-group>
</view>
<!-- 总价格 -->
<view class="total_price_wrap">
<view class="total_price">
合计:<text class="total_price_number">¥999</text>
</view>
<view>包含运费</view>
</view>
<!-- 结算 -->
<view class="order_pay_wrap">结算(1)</view>
</view>
效果如下
接下来需要进行的是默认选中已添加进购物车的商品,复选框内是选中状态。在goods_detail文件夹中index.js修改。
// pages/goods_detail/index.js
//引入用来发送请求的方法,优化后的
import {
request
} from "../../request/index.js"
Page({
/**
* 页面的初始数据
*/
data: {
//请求返回的数据是以对象形式
goodsObj: {}
},
//定义要预览的大图信息数组全局变量
goodsInfo: {},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
//拿到跳转页面时传递过来的商品id
const {
goods_id
} = options;
this.getGoodsDetail(goods_id);
},
/**
* 获取商品详情数据
*/
async getGoodsDetail(goods_id) {
const goodsObj = await request({
url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/detail",
data: {
goods_id
}
});
//请求成功之后给之前定义的预览大图数组赋值
this.goodsInfo = goodsObj.data.message;
this.setData({
// 优化存储数据,只赋值存储小程序用到的数据
goodsObj: {
goods_name: goodsObj.data.message.goods_name,
goods_price: goodsObj.data.message.goods_price,
// iphone部分手机不支持webp格式
// 后台修改
// 或者自己临时修改 使用replace函数 其中\.webp是找到所有.webp的文件,g表示全选,.jpg表示全部替换为.jpg格式。
goods_introduce: goodsObj.data.message.goods_introduce.replace(/\.webp/g, '.jpg'),
pics: goodsObj.data.message.pics
},
})
},
/**
* 点击轮播图预览大图事件
*/
handlePrevewImage(e) {
console.log('预览');
// 先构建要预览的图片数组
const urls = this.goodsInfo.pics.map(v => v.pics_mid)
// 接受传递过来的图片url
const current = e.currentTarget.dataset.url
wx.previewImage({
current: current,
urls: urls
})
},
/**
* 用户商品加入购物车事件
*/
handleCartAdd(e) {
//获取缓存的商品数据,并由字符串格式转为数组格式
let cart=wx.getStorageSync('cart')||[];
// 判定商品是否已存在购物车数组中
let index=cart.findIndex(v=>v.goods_id===this.goodsInfo.goods_id);
if(index===-1){
//不存在,第一次添加
this.goodsInfo.num=1;
// 给商品增添一个checked的属性,值为true,以便在购物车页面的复选框进行选中
this.goodsInfo.checked=true;
cart.push(this.goodsInfo);
}else{
//存在
cart[index].num++;
}
//购物车数组更新到缓存中
wx.setStorageSync("cart",cart);
//弹窗提示
wx.showToast({
title: '添加成功',
icon:'success',
mask:'true'
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
然后给cart文件夹下的index.wxml中的checkbox标签增添属性。
<!--pages/cart/index.wxml-->
<!-- 收货地址容器 -->
<view class="receive_address">
<!-- 收货地址按钮 -->
<!-- wx:if判断如果地址里边的用户名是否存在,不存在时显示 -->
<view class="address" wx:if="{{!address.userName}}">
<!-- plain表示按钮是否镂空,背景色透明 -->
<!-- 绑定点击事件,获取收货地址 -->
<button type="primary" plain="true" bindtap="handleChooseAddress">增添收货地址</button>
</view>
<!-- 当收货地址用户名存在,即有收货地址时 -->
<view wx:else class="user_info_row">
<view class="user_info">
<view> {{address.userName}}</view>
<view>{{address.all}}</view>
</view>
<view class="user_phone">
{{address.telNumber}}
</view>
</view>
</view>
<!-- 购物车具体内容 -->
<view class="cart_content">
<view class="cart_title">购物车</view>
<view class="cart_main">
<view class="cart_item" wx:for="{{cart}}" wx:key="goods_id">
<!-- 复选框结构 -->
<view class="cart_checkbox">
<checkbox-group bindchange="">
<checkbox checked="{{item.checked}}"></checkbox>
</checkbox-group>
</view>
<!-- 商品图片 -->
<navigator class="cart_image">
<image mode="widthFix"
src="{{item.goods_small_logo}}">
</image>
</navigator>
<!-- 商品信息 -->
<view class="cart_info">
<view class="goods_name">{{item.goods_name}}</view>
<view class="goods_price_wrap">
<view class="goods_price">{{item.goods_price}}</view>
<view class="cart_num_tool">
<view class="num_edit">-</view>
<view class="goods_nums">{{item.num}}</view>
<view class="num_edit">+</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 底部导航栏 -->
<view class="footer_tool">
<!-- 全选 -->
<view class="all_check_wrap">
<checkbox-group>
<checkbox>全选</checkbox>
</checkbox-group>
</view>
<!-- 总价格 -->
<view class="total_price_wrap">
<view class="total_price">
合计:<text class="total_price_number">¥999</text>
</view>
<view>包含运费</view>
</view>
<!-- 结算 -->
<view class="order_pay_wrap">结算(1)</view>
</view>
效果如下
接下来是底部导航栏的全选的实现,数据的动态更新。步骤如下
1.onShow中获取缓存中的购物车数组
2.根据购物车中的商品数据,当全部商品被选中时,全选被选中,有一个未被选中,全选按钮则不选中。
3.计算总价格和总数量,要商品被选中才进行。
4.获取缓存中购物车数组
5.遍历
6 总价格=商品的单价*商品数量
7.总数量=所有商品数量累加
8.计算后的价格数量更新到data中。
// pages/cart/index.js
Page({
// 点击获取收货地址事件
// 1.绑定点击事件
// 2.调用小程序内API,"wx.chooseAddress",获取用户的收货地址
// 购物车页面加载完毕
// 1.获取本地存储中的收货地址数据
// 2.如果有存储,就把数据 设置给data中的一个变量
handleChooseAddress(e) {
wx.chooseAddress({
success: (result) => {
// 把获取的地址存入本地缓存中,在存储之前先进行一个地址拼接
result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo;
console.log(result);
wx.setStorageSync('address', result)
},
});
},
/**
* 页面的初始数据
*/
data: {
address: {},
//声明一个变量,购物车数组
cart:[],
// 声明一个变量,购物车内容是否全选
allChecked:false,
// 定义商品总价格和总数量
totalPrice:0,
totalNum:0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
//获取缓存中的购物车数据
const cart=wx.getStorageSync('cart')
// 计算是否全选购物车商品
// every数组方法会遍历会接收个回调函数 那么每一个回调函数都返回true那么every方 法的返回值为true
// 只要有一个回调函数返回了false 那么不再循环执行,直接返回false
// 假如是空数组,那么every返回也是true,所以使用三元表达式
const allChecked=cart.length?cart.every(v=>v.checked):false;
//获取缓存中的收货地址信息
const address = wx.getStorageSync('address');
// 声明总价格和总数量
let totalPrice=0;
let totalNum=0;
cart.forEach(v=>{
if(v.checked){
totalPrice+=v.num*v.goods_price;
totalNum+=v.num;
}
})
//给data赋值
this.setData({
address,
cart:cart,
allChecked,
totalPrice,
totalNum
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
<!--pages/cart/index.wxml-->
<!-- 收货地址容器 -->
<view class="receive_address">
<!-- 收货地址按钮 -->
<!-- wx:if判断如果地址里边的用户名是否存在,不存在时显示 -->
<view class="address" wx:if="{{!address.userName}}">
<!-- plain表示按钮是否镂空,背景色透明 -->
<!-- 绑定点击事件,获取收货地址 -->
<button type="primary" plain="true" bindtap="handleChooseAddress">增添收货地址</button>
</view>
<!-- 当收货地址用户名存在,即有收货地址时 -->
<view wx:else class="user_info_row">
<view class="user_info">
<view> {{address.userName}}</view>
<view>{{address.all}}</view>
</view>
<view class="user_phone">
{{address.telNumber}}
</view>
</view>
</view>
<!-- 购物车具体内容 -->
<view class="cart_content">
<view class="cart_title">购物车</view>
<view class="cart_main">
<view class="cart_item" wx:for="{{cart}}" wx:key="goods_id">
<!-- 复选框结构 -->
<view class="cart_checkbox">
<checkbox-group bindchange="">
<checkbox checked="{{item.checked}}"></checkbox>
</checkbox-group>
</view>
<!-- 商品图片 -->
<navigator class="cart_image">
<image mode="widthFix"
src="{{item.goods_small_logo}}">
</image>
</navigator>
<!-- 商品信息 -->
<view class="cart_info">
<view class="goods_name">{{item.goods_name}}</view>
<view class="goods_price_wrap">
<view class="goods_price">{{item.goods_price}}</view>
<view class="cart_num_tool">
<view class="num_edit">-</view>
<view class="goods_nums">{{item.num}}</view>
<view class="num_edit">+</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 底部导航栏 -->
<view class="footer_tool">
<!-- 全选 -->
<view class="all_check_wrap">
<checkbox-group>
<checkbox checked="{{allChecked}}">全选</checkbox>
</checkbox-group>
</view>
<!-- 总价格 -->
<view class="total_price_wrap">
<view class="total_price">
合计:<text class="total_price_number">¥{{totalPrice}}</text>
</view>
<view>包含运费</view>
</view>
<!-- 结算 -->
<view class="order_pay_wrap">结算({{totalNum}})</view>
</view>
商品的选中功能优化
1.绑定change事件
2.获取到被修改的商品对象
3.商品对象的选中状态取反
4.重新填充回data中和缓存中
5.重新计算全选。总价格总数量
// pages/cart/index.js
Page({
/**
* 封装一个函数,设置购物车商品状态的同时,底部工具栏,总价格,总数量重新计算
*/
setCart(cart) {
let allChecked = true;
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
} else {
allChecked = false;
}
})
//判断数组是否为空
allChecked = cart.length != 0 ? allChecked : false;
this.setData({
cart,
totalPrice,
totalNum,
allChecked
});
wx.setStorageSync('cart', cart);
},
// 点击获取收货地址事件
// 1.绑定点击事件
// 2.调用小程序内API,"wx.chooseAddress",获取用户的收货地址
// 购物车页面加载完毕
// 1.获取本地存储中的收货地址数据
// 2.如果有存储,就把数据 设置给data中的一个变量
handleChooseAddress(e) {
wx.chooseAddress({
success: (result) => {
// 把获取的地址存入本地缓存中,在存储之前先进行一个地址拼接
result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo;
console.log(result);
wx.setStorageSync('address', result)
},
});
},
// 商品的选中优化事件
handleItemChange(e) {
//获取被修改的商品id
const goods_id = e.currentTarget.dataset.id;
// 获取购物车数组
let {
cart
} = this.data;
//找到购物车数组中要被修改的商品对象
let index = cart.findIndex(v => v.goods_id === goods_id);
// 修改商品对象的选中状态,取反
cart[index].checked = !cart[index].checked;
// 将此时的数据更新到data和缓存中,并重新计算总价格和总数量,通过调用封装的函数setCart实现
this.setCart(cart);
},
/**
* 页面的初始数据
*/
data: {
address: {},
//声明一个变量,购物车数组
cart: [],
// 声明一个变量,购物车内容是否全选
allChecked: false,
// 定义商品总价格和总数量
totalPrice: 0,
totalNum: 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
//获取缓存中的购物车数据
const cart = wx.getStorageSync('cart')
// 计算是否全选购物车商品
// every数组方法会遍历会接收个回调函数 那么每一个回调函数都返回true那么every方 法的返回值为true
// 只要有一个回调函数返回了false 那么不再循环执行,直接返回false
// 假如是空数组,那么every返回也是true,所以使用三元表达式
const allChecked = cart.length ? cart.every(v => v.checked) : false;
//获取缓存中的收货地址信息
const address = wx.getStorageSync('address');
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
}
})
//给data赋值
this.setData({
address,
cart: cart,
allChecked,
totalPrice,
totalNum
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
<!--pages/cart/index.wxml-->
<!-- 收货地址容器 -->
<view class="receive_address">
<!-- 收货地址按钮 -->
<!-- wx:if判断如果地址里边的用户名是否存在,不存在时显示 -->
<view class="address" wx:if="{{!address.userName}}">
<!-- plain表示按钮是否镂空,背景色透明 -->
<!-- 绑定点击事件,获取收货地址 -->
<button type="primary" plain="true" bindtap="handleChooseAddress">增添收货地址</button>
</view>
<!-- 当收货地址用户名存在,即有收货地址时 -->
<view wx:else class="user_info_row">
<view class="user_info">
<view> {{address.userName}}</view>
<view>{{address.all}}</view>
</view>
<view class="user_phone">
{{address.telNumber}}
</view>
</view>
</view>
<!-- 购物车具体内容 -->
<view class="cart_content">
<view class="cart_title">购物车</view>
<view class="cart_main">
<view class="cart_item" wx:for="{{cart}}" wx:key="goods_id">
<!-- 复选框结构 -->
<view class="cart_checkbox">
<checkbox-group data-id="{{item.goods_id}}" bindchange="handleItemChange">
<checkbox checked="{{item.checked}}"></checkbox>
</checkbox-group>
</view>
<!-- 商品图片 -->
<navigator class="cart_image">
<image mode="widthFix"
src="{{item.goods_small_logo}}">
</image>
</navigator>
<!-- 商品信息 -->
<view class="cart_info">
<view class="goods_name">{{item.goods_name}}</view>
<view class="goods_price_wrap">
<view class="goods_price">{{item.goods_price}}</view>
<view class="cart_num_tool">
<view class="num_edit">-</view>
<view class="goods_nums">{{item.num}}</view>
<view class="num_edit">+</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 底部导航栏 -->
<view class="footer_tool">
<!-- 全选 -->
<view class="all_check_wrap">
<checkbox-group>
<checkbox checked="{{allChecked}}">全选</checkbox>
</checkbox-group>
</view>
<!-- 总价格 -->
<view class="total_price_wrap">
<view class="total_price">
合计:<text class="total_price_number">¥{{totalPrice}}</text>
</view>
<view>包含运费</view>
</view>
<!-- 结算 -->
<view class="order_pay_wrap">结算({{totalNum}})</view>
</view>
效果如下
接下来是点击购物车页面的全选按钮,则页面内所有商品全部被选中。步骤如下
1全选复选框绑定事件change
2获取data中的全选变量allChecked
3直接取反allChecked= ! allChecked
4遍历购物车数组让里面商品选中状态跟随 allChecked 改变而改变
5把购物车数组和allChecked 重新设置回data把购物车重新设置回缓存中
// pages/cart/index.js
Page({
/**
* 封装一个函数,设置购物车商品状态的同时,底部工具栏,总价格,总数量重新计算
*/
setCart(cart) {
let allChecked = true;
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
} else {
allChecked = false;
}
})
//判断数组是否为空
allChecked = cart.length != 0 ? allChecked : false;
this.setData({
cart,
totalPrice,
totalNum,
allChecked
});
wx.setStorageSync('cart', cart);
},
// 点击获取收货地址事件
// 1.绑定点击事件
// 2.调用小程序内API,"wx.chooseAddress",获取用户的收货地址
// 购物车页面加载完毕
// 1.获取本地存储中的收货地址数据
// 2.如果有存储,就把数据 设置给data中的一个变量
handleChooseAddress(e) {
wx.chooseAddress({
success: (result) => {
// 把获取的地址存入本地缓存中,在存储之前先进行一个地址拼接
result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo;
console.log(result);
wx.setStorageSync('address', result)
},
});
},
// 商品的选中优化事件
handleItemChange(e) {
//获取被修改的商品id
const goods_id = e.currentTarget.dataset.id;
// 获取购物车数组
let {
cart
} = this.data;
//找到购物车数组中要被修改的商品对象
let index = cart.findIndex(v => v.goods_id === goods_id);
// 修改商品对象的选中状态,取反
cart[index].checked = !cart[index].checked;
// 将此时的数据更新到data和缓存中,并重新计算总价格和总数量,通过调用封装的函数setCart实现
this.setCart(cart);
},
//商品的全选功能
handleItemAllChecked(e) {
// 1获取data中的数据
let {
cart,
allChecked
} = this.data;
// 2修改值
allChecked = !allChecked;
// 3循环修改cart数组中的商品选中状态
cart.forEach(v => v.checked = allChecked);
// 4把修改后的值填充回data或者缓存中,通过调用封装好的函数
this.setCart(cart);
},
/**
* 页面的初始数据
*/
data: {
address: {},
//声明一个变量,购物车数组
cart: [],
// 声明一个变量,购物车内容是否全选
allChecked: false,
// 定义商品总价格和总数量
totalPrice: 0,
totalNum: 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
//获取缓存中的购物车数据
const cart = wx.getStorageSync('cart')
// 计算是否全选购物车商品
// every数组方法会遍历会接收个回调函数 那么每一个回调函数都返回true那么every方 法的返回值为true
// 只要有一个回调函数返回了false 那么不再循环执行,直接返回false
// 假如是空数组,那么every返回也是true,所以使用三元表达式
const allChecked = cart.length ? cart.every(v => v.checked) : false;
//获取缓存中的收货地址信息
const address = wx.getStorageSync('address');
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
}
})
//给data赋值
this.setData({
address,
cart: cart,
allChecked,
totalPrice,
totalNum
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
<!--pages/cart/index.wxml-->
<!-- 收货地址容器 -->
<view class="receive_address">
<!-- 收货地址按钮 -->
<!-- wx:if判断如果地址里边的用户名是否存在,不存在时显示 -->
<view class="address" wx:if="{{!address.userName}}">
<!-- plain表示按钮是否镂空,背景色透明 -->
<!-- 绑定点击事件,获取收货地址 -->
<button type="primary" plain="true" bindtap="handleChooseAddress">增添收货地址</button>
</view>
<!-- 当收货地址用户名存在,即有收货地址时 -->
<view wx:else class="user_info_row">
<view class="user_info">
<view> {{address.userName}}</view>
<view>{{address.all}}</view>
</view>
<view class="user_phone">
{{address.telNumber}}
</view>
</view>
</view>
<!-- 购物车具体内容 -->
<view class="cart_content">
<view class="cart_title">购物车</view>
<view class="cart_main">
<view class="cart_item" wx:for="{{cart}}" wx:key="goods_id">
<!-- 复选框结构 -->
<view class="cart_checkbox">
<checkbox-group data-id="{{item.goods_id}}" bindchange="handleItemChange">
<checkbox checked="{{item.checked}}"></checkbox>
</checkbox-group>
</view>
<!-- 商品图片 -->
<navigator class="cart_image">
<image mode="widthFix"
src="{{item.goods_small_logo}}">
</image>
</navigator>
<!-- 商品信息 -->
<view class="cart_info">
<view class="goods_name">{{item.goods_name}}</view>
<view class="goods_price_wrap">
<view class="goods_price">{{item.goods_price}}</view>
<view class="cart_num_tool">
<view class="num_edit">-</view>
<view class="goods_nums">{{item.num}}</view>
<view class="num_edit">+</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 底部导航栏 -->
<view class="footer_tool">
<!-- 全选 -->
<view class="all_check_wrap">
<checkbox-group bindchange="handleItemAllChecked">
<checkbox checked="{{allChecked}}">全选</checkbox>
</checkbox-group>
</view>
<!-- 总价格 -->
<view class="total_price_wrap">
<view class="total_price">
合计:<text class="total_price_number">¥{{totalPrice}}</text>
</view>
<view>包含运费</view>
</view>
<!-- 结算 -->
<view class="order_pay_wrap">结算({{totalNum}})</view>
</view>
最后效果如下,每次点击全选按钮,上边的商品都会被全选中,或者全不被选中。
点击单个商品后的加或减按钮,则商品的数量发生变更,同时总数量和总价格发生改变。步骤如下
wx.showModal
。// pages/cart/index.js
Page({
/**
* 封装一个函数,设置购物车商品状态的同时,底部工具栏,总价格,总数量重新计算
*/
setCart(cart) {
let allChecked = true;
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
} else {
allChecked = false;
}
})
//判断数组是否为空
allChecked = cart.length != 0 ? allChecked : false;
this.setData({
cart,
totalPrice,
totalNum,
allChecked
});
wx.setStorageSync('cart', cart);
},
// 点击获取收货地址事件
// 1.绑定点击事件
// 2.调用小程序内API,"wx.chooseAddress",获取用户的收货地址
// 购物车页面加载完毕
// 1.获取本地存储中的收货地址数据
// 2.如果有存储,就把数据 设置给data中的一个变量
handleChooseAddress(e) {
wx.chooseAddress({
success: (result) => {
// 把获取的地址存入本地缓存中,在存储之前先进行一个地址拼接
result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo;
console.log(result);
wx.setStorageSync('address', result)
},
});
},
// 商品的选中优化事件
handleItemChange(e) {
//获取被修改的商品id
const goods_id = e.currentTarget.dataset.id;
// 获取购物车数组
let {
cart
} = this.data;
//找到购物车数组中要被修改的商品对象
let index = cart.findIndex(v => v.goods_id === goods_id);
// 修改商品对象的选中状态,取反
cart[index].checked = !cart[index].checked;
// 将此时的数据更新到data和缓存中,并重新计算总价格和总数量,通过调用封装的函数setCart实现
this.setCart(cart);
},
//商品的全选功能
handleItemAllChecked(e) {
// 1获取data中的数据
let {
cart,
allChecked
} = this.data;
// 2修改值
allChecked = !allChecked;
// 3循环修改cart数组中的商品选中状态
cart.forEach(v => v.checked = allChecked);
// 4把修改后的值填充回data或者缓存中,通过调用封装好的函数
this.setCart(cart);
},
//商品数量加减功能
handleItemNumEdit(e) {
// 1获取传递过来的参 数
const {
operation,
id
} = e.currentTarget.dataset;
// 2获取购物车数组
let {
cart
} = this.data;
//3找到需要修改的商品的索引
const index = cart.findIndex(v => v.goods_id === id);
//判定商品数量小于1时,是否要被删除
if(cart[index].num===1&&operation===-1){
wx.showModal({
title: '提示',
content: '您是否要删除该商品?',
success:(res)=>{
if (res.confirm) {
cart.splice(index,1);
this.setCart(cart);
} else if (res.cancel) {
console.log('用户点击取消');
}
}
})
}else{
// 4进行修改数量
cart[index].num += operation;
// 5设置回缓存和data中
this.setCart(cart);}
},
/**
* 页面的初始数据
*/
data: {
address: {},
//声明一个变量,购物车数组
cart: [],
// 声明一个变量,购物车内容是否全选
allChecked: false,
// 定义商品总价格和总数量
totalPrice: 0,
totalNum: 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
//获取缓存中的购物车数据
const cart = wx.getStorageSync('cart')
// 计算是否全选购物车商品
// every数组方法会遍历会接收个回调函数 那么每一个回调函数都返回true那么every方 法的返回值为true
// 只要有一个回调函数返回了false 那么不再循环执行,直接返回false
// 假如是空数组,那么every返回也是true,所以使用三元表达式
const allChecked = cart.length ? cart.every(v => v.checked) : false;
//获取缓存中的收货地址信息
const address = wx.getStorageSync('address');
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
}
})
//给data赋值
this.setData({
address,
cart: cart,
allChecked,
totalPrice,
totalNum
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
<!--pages/cart/index.wxml-->
<!-- 收货地址容器 -->
<view class="receive_address">
<!-- 收货地址按钮 -->
<!-- wx:if判断如果地址里边的用户名是否存在,不存在时显示 -->
<view class="address" wx:if="{{!address.userName}}">
<!-- plain表示按钮是否镂空,背景色透明 -->
<!-- 绑定点击事件,获取收货地址 -->
<button type="primary" plain="true" bindtap="handleChooseAddress">增添收货地址</button>
</view>
<!-- 当收货地址用户名存在,即有收货地址时 -->
<view wx:else class="user_info_row">
<view class="user_info">
<view> {{address.userName}}</view>
<view>{{address.all}}</view>
</view>
<view class="user_phone">
{{address.telNumber}}
</view>
</view>
</view>
<!-- 购物车具体内容 -->
<view class="cart_content">
<view class="cart_title">购物车</view>
<view class="cart_main">
<view class="cart_item" wx:for="{{cart}}" wx:key="goods_id">
<!-- 复选框结构 -->
<view class="cart_checkbox">
<checkbox-group data-id="{{item.goods_id}}" bindchange="handleItemChange">
<checkbox checked="{{item.checked}}"></checkbox>
</checkbox-group>
</view>
<!-- 商品图片 -->
<navigator class="cart_image">
<image mode="widthFix"
src="{{item.goods_small_logo}}">
</image>
</navigator>
<!-- 商品信息 -->
<view class="cart_info">
<view class="goods_name">{{item.goods_name}}</view>
<view class="goods_price_wrap">
<view class="goods_price">{{item.goods_price}}</view>
<view class="cart_num_tool">
<view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{-1}}">-</view>
<view class="goods_nums">{{item.num}}</view>
<view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{1}}">+</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 底部导航栏 -->
<view class="footer_tool">
<!-- 全选 -->
<view class="all_check_wrap">
<checkbox-group bindchange="handleItemAllChecked">
<checkbox checked="{{allChecked}}">全选</checkbox>
</checkbox-group>
</view>
<!-- 总价格 -->
<view class="total_price_wrap">
<view class="total_price">
合计:<text class="total_price_number">¥{{totalPrice}}</text>
</view>
<view>包含运费</view>
</view>
<!-- 结算 -->
<view class="order_pay_wrap">结算({{totalNum}})</view>
</view>
查看cart中的数组长度,如果为0,则表示没商品,否则判断为有商品。直接在index.wxml中使用block标签即可完成。
<!--pages/cart/index.wxml-->
<!-- 收货地址容器 -->
<view class="receive_address">
<!-- 收货地址按钮 -->
<!-- wx:if判断如果地址里边的用户名是否存在,不存在时显示 -->
<view class="address" wx:if="{{!address.userName}}">
<!-- plain表示按钮是否镂空,背景色透明 -->
<!-- 绑定点击事件,获取收货地址 -->
<button type="primary" plain="true" bindtap="handleChooseAddress">增添收货地址</button>
</view>
<!-- 当收货地址用户名存在,即有收货地址时 -->
<view wx:else class="user_info_row">
<view class="user_info">
<view> {{address.userName}}</view>
<view>{{address.all}}</view>
</view>
<view class="user_phone">
{{address.telNumber}}
</view>
</view>
</view>
<!-- 购物车具体内容 -->
<view class="cart_content">
<view class="cart_title">购物车</view>
<view class="cart_main">
<!-- 当cart数组的长度不为0时,则显示商品信息 -->
<block wx:if="{{cart.length!==0}}">
<view class="cart_item" wx:for="{{cart}}" wx:key="goods_id">
<!-- 复选框结构 -->
<view class="cart_checkbox">
<checkbox-group data-id="{{item.goods_id}}" bindchange="handleItemChange">
<checkbox checked="{{item.checked}}"></checkbox>
</checkbox-group>
</view>
<!-- 商品图片 -->
<navigator class="cart_image">
<image mode="widthFix" src="{{item.goods_small_logo}}">
</image>
</navigator>
<!-- 商品信息 -->
<view class="cart_info">
<view class="goods_name">{{item.goods_name}}</view>
<view class="goods_price_wrap">
<view class="goods_price">{{item.goods_price}}</view>
<view class="cart_num_tool">
<view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{-1}}">-
</view>
<view class="goods_nums">{{item.num}}</view>
<view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{1}}">+
</view>
</view>
</view>
</view>
</view>
</block>
<!-- 当商品cart中的数组长度为0时,表示没有商品 -->
<block wx:else>
<image mode="widthFix"
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.mp.itc.cn%2Fupload%2F20170401%2F2f523043409747a9b68c1bcf6fd353a5_th.jpeg&refer=http%3A%2F%2Fimg.mp.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1637485819&t=36e036c0adbfcb56e7658e4730b87461">
</image>
</block>
</view>
</view>
<!-- 底部导航栏 -->
<view class="footer_tool">
<!-- 全选 -->
<view class="all_check_wrap">
<checkbox-group bindchange="handleItemAllChecked">
<checkbox checked="{{allChecked}}">全选</checkbox>
</checkbox-group>
</view>
<!-- 总价格 -->
<view class="total_price_wrap">
<view class="total_price">
合计:<text class="total_price_number">¥{{totalPrice}}</text>
</view>
<view>包含运费</view>
</view>
<!-- 结算 -->
<view class="order_pay_wrap">结算({{totalNum}})</view>
</view>
效果如下
结算功能的实现,前提是有收货地址,并且有商品存在。然后跳转到支付页面。使用到了wx.showToast
和wx.navigateTo
的微信内置API。
// pages/cart/index.js
Page({
/**
* 封装一个函数,设置购物车商品状态的同时,底部工具栏,总价格,总数量重新计算
*/
setCart(cart) {
let allChecked = true;
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
} else {
allChecked = false;
}
})
//判断数组是否为空
allChecked = cart.length != 0 ? allChecked : false;
this.setData({
cart,
totalPrice,
totalNum,
allChecked
});
wx.setStorageSync('cart', cart);
},
// 点击获取收货地址事件
// 1.绑定点击事件
// 2.调用小程序内API,"wx.chooseAddress",获取用户的收货地址
// 购物车页面加载完毕
// 1.获取本地存储中的收货地址数据
// 2.如果有存储,就把数据 设置给data中的一个变量
handleChooseAddress(e) {
wx.chooseAddress({
success: (result) => {
// 把获取的地址存入本地缓存中,在存储之前先进行一个地址拼接
result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo;
console.log(result);
wx.setStorageSync('address', result)
},
});
},
// 商品的选中优化事件
handleItemChange(e) {
//获取被修改的商品id
const goods_id = e.currentTarget.dataset.id;
// 获取购物车数组
let {
cart
} = this.data;
//找到购物车数组中要被修改的商品对象
let index = cart.findIndex(v => v.goods_id === goods_id);
// 修改商品对象的选中状态,取反
cart[index].checked = !cart[index].checked;
// 将此时的数据更新到data和缓存中,并重新计算总价格和总数量,通过调用封装的函数setCart实现
this.setCart(cart);
},
//商品的全选功能
handleItemAllChecked(e) {
// 1获取data中的数据
let {
cart,
allChecked
} = this.data;
// 2修改值
allChecked = !allChecked;
// 3循环修改cart数组中的商品选中状态
cart.forEach(v => v.checked = allChecked);
// 4把修改后的值填充回data或者缓存中,通过调用封装好的函数
this.setCart(cart);
},
//商品数量加减功能
handleItemNumEdit(e) {
// 1获取传递过来的参 数
const {
operation,
id
} = e.currentTarget.dataset;
// 2获取购物车数组
let {
cart
} = this.data;
//3找到需要修改的商品的索引
const index = cart.findIndex(v => v.goods_id === id);
//判定商品数量小于1时,是否要被删除
if (cart[index].num === 1 && operation === -1) {
wx.showModal({
title: '提示',
content: '您是否要删除该商品?',
success: (res) => {
if (res.confirm) {
cart.splice(index, 1);
this.setCart(cart);
} else if (res.cancel) {
console.log('用户点击取消');
}
}
})
} else {
// 4进行修改数量
cart[index].num += operation;
// 5设置回缓存和data中
this.setCart(cart);
}
},
// 商品页面的结算功能
handlePay(e) {
//1. 判断收货地址和是否有商品数量
const {
address,
totalNum
} = this.data;
if (!address.userName) {
wx.showToast({
title: '请添加收货地址',
icon: 'error',
duration: 2000,
})
return;
}
if (totalNum===0) {
wx.showToast({
title: '请添加商品',
icon: 'error',
duration: 2000
})
return;
}
// 跳转到微信支付页面
wx.navigateTo({
url: '/pages/pay/index',
})
},
/**
* 页面的初始数据
*/
data: {
address: {},
//声明一个变量,购物车数组
cart: [],
// 声明一个变量,购物车内容是否全选
allChecked: false,
// 定义商品总价格和总数量
totalPrice: 0,
totalNum: 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
//获取缓存中的购物车数据
const cart = wx.getStorageSync('cart')
// 计算是否全选购物车商品
// every数组方法会遍历会接收个回调函数 那么每一个回调函数都返回true那么every方 法的返回值为true
// 只要有一个回调函数返回了false 那么不再循环执行,直接返回false
// 假如是空数组,那么every返回也是true,所以使用三元表达式
const allChecked = cart.length ? cart.every(v => v.checked) : false;
//获取缓存中的收货地址信息
const address = wx.getStorageSync('address');
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
}
})
//给data赋值
this.setData({
address,
cart: cart,
allChecked,
totalPrice,
totalNum
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
<!--pages/cart/index.wxml-->
<!-- 收货地址容器 -->
<view class="receive_address">
<!-- 收货地址按钮 -->
<!-- wx:if判断如果地址里边的用户名是否存在,不存在时显示 -->
<view class="address" wx:if="{{!address.userName}}">
<!-- plain表示按钮是否镂空,背景色透明 -->
<!-- 绑定点击事件,获取收货地址 -->
<button type="primary" plain="true" bindtap="handleChooseAddress">增添收货地址</button>
</view>
<!-- 当收货地址用户名存在,即有收货地址时 -->
<view wx:else class="user_info_row">
<view class="user_info">
<view> {{address.userName}}</view>
<view>{{address.all}}</view>
</view>
<view class="user_phone">
{{address.telNumber}}
</view>
</view>
</view>
<!-- 购物车具体内容 -->
<view class="cart_content">
<view class="cart_title">购物车</view>
<view class="cart_main">
<!-- 当cart数组的长度不为0时,则显示商品信息 -->
<block wx:if="{{cart.length!==0}}">
<view class="cart_item" wx:for="{{cart}}" wx:key="goods_id">
<!-- 复选框结构 -->
<view class="cart_checkbox">
<checkbox-group data-id="{{item.goods_id}}" bindchange="handleItemChange">
<checkbox checked="{{item.checked}}"></checkbox>
</checkbox-group>
</view>
<!-- 商品图片 -->
<navigator class="cart_image">
<image mode="widthFix" src="{{item.goods_small_logo}}">
</image>
</navigator>
<!-- 商品信息 -->
<view class="cart_info">
<view class="goods_name">{{item.goods_name}}</view>
<view class="goods_price_wrap">
<view class="goods_price">{{item.goods_price}}</view>
<view class="cart_num_tool">
<view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{-1}}">-
</view>
<view class="goods_nums">{{item.num}}</view>
<view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{1}}">+
</view>
</view>
</view>
</view>
</view>
</block>
<!-- 当商品cart中的数组长度为0时,表示没有商品 -->
<block wx:else>
<image mode="widthFix"
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.mp.itc.cn%2Fupload%2F20170401%2F2f523043409747a9b68c1bcf6fd353a5_th.jpeg&refer=http%3A%2F%2Fimg.mp.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1637485819&t=36e036c0adbfcb56e7658e4730b87461">
</image>
</block>
</view>
</view>
<!-- 底部导航栏 -->
<view class="footer_tool">
<!-- 全选 -->
<view class="all_check_wrap">
<checkbox-group bindchange="handleItemAllChecked">
<checkbox checked="{{allChecked}}">全选</checkbox>
</checkbox-group>
</view>
<!-- 总价格 -->
<view class="total_price_wrap">
<view class="total_price">
合计:<text class="total_price_number">¥{{totalPrice}}</text>
</view>
<view>包含运费</view>
</view>
<!-- 结算 -->
<view class="order_pay_wrap" bindtap="handlePay">结算({{totalNum}})</view>
</view>
pay文件夹对应的为支付页面,首先是修改页面的名称,在index.json中修改,如下。
{
"usingComponents": {},
"navigationBarTitleText": "支付"
}
随后页面发生变化
支付页面整体风格与购物车页面相似,所以这里可以大段复制之前购物车页面的代码。然后进行细微修改。
<!--pages/pay/index.wxml-->
<!-- 收货地址容器 -->
<view class="receive_address">
<view class="user_info_row">
<view class="user_info">
<view> {{address.userName}}</view>
<view>{{address.all}}</view>
</view>
<view class="user_phone">
{{address.telNumber}}
</view>
</view>
</view>
<!-- 购物车具体内容 -->
<view class="cart_content">
<view class="cart_title">购物车</view>
<view class="cart_main">
<view class="cart_item" wx:for="{{cart}}" wx:key="goods_id">
<!-- 商品图片 -->
<navigator class="cart_image">
<image mode="widthFix" src="{{item.goods_small_logo}}">
</image>
</navigator>
<!-- 商品信息 -->
<view class="cart_info">
<view class="goods_name">{{item.goods_name}}</view>
<view class="goods_price_wrap">
<view class="goods_price">{{item.goods_price}}</view>
<view class="cart_num_tool">
<view class="goods_nums">x{{item.num}}</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 底部导航栏 -->
<view class="footer_tool">
<!-- 总价格 -->
<view class="total_price_wrap">
<view class="total_price">
合计:<text class="total_price_number">¥{{totalPrice}}</text>
</view>
<view>包含运费</view>
</view>
<!-- 支付 -->
<view class="order_pay_wrap">支付({{totalNum}})</view>
</view>
/* pages/pay/index.wxss */
page{
padding-bottom: 90rpx;
}
.address {
padding: 20rpx;
}
.address button {
width: 60%;
}
.user_info_row {
display: flex;
padding: 20rpx;
}
.user_info {
flex: 5;
}
.user_phone {
flex: 2;
text-align: center;
justify-content: center;
}
.cart_title {
padding: 20rpx;
font-size: 36rpx;
color: var(--themColor);
border-top: 1rpx solid currentColor;
border-bottom: 1rpx solid currentColor;
}
.cart_item {
display: flex;
}
.cart_item .cart_image {
flex: 2;
display: flex;
justify-content: center;
align-items: center;
}
.cart_image image {
width: 80%;
}
.cart_info {
flex: 4;
display: flex;
justify-content: space-around;
flex-direction: column;
}
.cart_info .goods_name {
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
color: #666;
}
.cart_info .goods_price_wrap {
display: flex;
justify-content: space-between;
}
.goods_price {
color: var(--themColor);
font-size: 34rpx;
}
.cart_num_tool {
display: flex;
}
.goods_nums {
width: 55rpx;
height: 55rpx;
display: flex;
justify-content: center;
align-items: center;
}
.footer_tool{
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 90rpx;
background-color: #fff;
display: flex;
border-top: 1rpx solid #ccc;
}
.total_price_wrap{
flex: 4;
padding-right: 15rpx;
/* 文字右对齐 */
text-align: right;
}
.total_price_number{
color: var(--themColor);
font-size: 34rpx;
font-weight: 600;
}
.order_pay_wrap{
flex: 2;
background-color: var(--themColor);
color: #fff;
font-size: 32rpx;
font-weight: 600;
display: flex;
justify-content: center;
align-items: center;
}
// pages/pay/index.js
Page({
/**
* 封装一个函数,设置商品状态的同时,底部工具栏,总价格,总数量重新计算
*/
setCart(cart) {
let allChecked = true;
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
} else {
allChecked = false;
}
})
//判断数组是否为空
allChecked = cart.length != 0 ? allChecked : false;
this.setData({
cart,
totalPrice,
totalNum,
});
wx.setStorageSync('cart', cart);
},
/**
* 页面的初始数据
*/
data: {
address: {},
//声明一个变量,购物车数组
cart: [],
// 声明一个变量,购物车内容是否全选
allChecked: false,
// 定义商品总价格和总数量
totalPrice: 0,
totalNum: 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
//获取缓存中的购物车数据
const cart = wx.getStorageSync('cart')
// 计算是否全选购物车商品
// every数组方法会遍历会接收个回调函数 那么每一个回调函数都返回true那么every方 法的返回值为true
// 只要有一个回调函数返回了false 那么不再循环执行,直接返回false
// 假如是空数组,那么every返回也是true,所以使用三元表达式
const allChecked = cart.length ? cart.every(v => v.checked) : false;
//获取缓存中的收货地址信息
const address = wx.getStorageSync('address');
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
}
})
//给data赋值
this.setData({
address,
cart: cart,
allChecked,
totalPrice,
totalNum
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
最终经过修改后的支付页面样式如下
接下来是一些相关的支付逻辑,对于在此页的商品,我们必须要保证他曾经是在购物车页面被选中过的,即checkbox被选中为true的。所以需要在index.js内进行过滤,筛选真正需要支付的。
// pages/pay/index.js
Page({
/**
* 封装一个函数,设置商品状态的同时,底部工具栏,总价格,总数量重新计算
*/
setCart(cart) {
let allChecked = true;
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
} else {
allChecked = false;
}
})
//判断数组是否为空
allChecked = cart.length != 0 ? allChecked : false;
this.setData({
cart,
totalPrice,
totalNum,
});
wx.setStorageSync('cart', cart);
},
/**
* 页面的初始数据
*/
data: {
address: {},
//声明一个变量,购物车数组
cart: [],
// 声明一个变量,购物车内容是否全选
allChecked: false,
// 定义商品总价格和总数量
totalPrice: 0,
totalNum: 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
//获取缓存中的购物车数据
let cart = wx.getStorageSync('cart')
//获取缓存中的收货地址信息
const address = wx.getStorageSync('address');
//过滤后的购物车数组(真正被选中的商品)
cart = cart.filter(v => v.checked);
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
})
this.setData({
cart,
totalPrice,
totalNum, address,
});
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
可以看到购物车有三件商品,只结算两件,跳转到支付页面之后,确实只有两件商品。
现在来实现点击支付按钮,进行微信支付功能。微信支付有哪些人或者帐号可以实现呢?目前来说,只有企业帐号开发的小程序可以实现,并且企业帐号的小程序后台中必须给开发者添加上白名单。具体详细信息,需要查看小程序开发文档(微信支付)。
总体流程如下
实际上应用的流程如下,当点击支付按钮时,先判断缓存中有没有用户登录时的token值,若没有,则跳转到授权页面,获取token,若有token值,则进行创建订单步骤。此时支付页面的index.js代码如下,因为没有token值,所以点击支付后跳转到了auth页面,进行授权。
// pages/pay/index.js
Page({
/**
* 封装一个函数,设置商品状态的同时,底部工具栏,总价格,总数量重新计算
*/
setCart(cart) {
let allChecked = true;
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
} else {
allChecked = false;
}
})
//判断数组是否为空
allChecked = cart.length != 0 ? allChecked : false;
this.setData({
cart,
totalPrice,
totalNum,
});
wx.setStorageSync('cart', cart);
},
/**
* 页面的初始数据
*/
data: {
address: {},
//声明一个变量,购物车数组
cart: [],
// 声明一个变量,购物车内容是否全选
allChecked: false,
// 定义商品总价格和总数量
totalPrice: 0,
totalNum: 0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
//获取缓存中的购物车数据
let cart = wx.getStorageSync('cart')
//获取缓存中的收货地址信息
const address = wx.getStorageSync('address');
//过滤后的购物车数组(真正被选中的商品)
cart = cart.filter(v => v.checked);
// 声明总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
})
this.setData({
cart,
totalPrice,
totalNum,
address,
});
},
// 点击支付事件
handleOrderPay(e) {
//判断缓存中有无token
const token = wx.getStorageSync('token');
//如果不存在
if (!token) {
//跳转页面到获取用户登录信息
wx.navigateTo({
url: '/pages/auth/index',
})
return;
}
//否则就是有token值
console.log('已经有token了');
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
auth文件夹下,首先是在index.json中进行修改页面的名字 。
{
"usingComponents": {},
"navigationBarTitleText": "授权"
}
随后在该文件夹下的index.wxml代码中添加一个按钮,点击就进行授权。
<!--pages/auth/index.wxml-->
<!-- 获取用户授权,绑定点击事件 -->
<button type="primary" plain="true" open-type="getUserInfo" bindgetuserinfo="handleGetUserInfo">
获取授权
</button>
index.wxss样式如下
/* pages/auth/index.wxss */
button{
margin-top: 40rpx;
width: 70%;
}
然后在index.js中书写 相关逻辑代码,注意这里我们自定义了一个token值,因为我们不是企业微信。
// pages/auth/index.js
// 引入封装好的请求函数
import {
request
} from "../../request/index.js"
Page({
//获取用户信息
async handleGetUserInfo(e) {
// 打印下点击后获得的事件e
// console.log(e);
// 获取事件e中的如下属性。
const {
encryptedData,
rawData,
iv,
signature
} = e.detail;
//获取小程序登录成功后的code值
wx.login({
timeout: 10000,
success: (result) => {
// 查看得到了code值
// console.log(result);
const code = result.code;
wx.setStorageSync('code', code)
},
fail: () => {},
complete: () => {}
})
const code = wx.getStorageSync('code');
const loginParams = {
encryptedData,
rawData,
iv,
signature,
code
};
//发送请求,获取用户的token值
const token = await request({
url: "https://api-hmugo-web.itheima.net/api/public/v1/users/wxlogin",
data: this.loginParams,
method: "post"
});
//把token存入到缓存中,同时跳转回上一个页面(这里我们使用了一个自定义的token,因为我们不是企业微信账户)
wx.setStorageSync('token', 'BearereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjIzLCJpYXQiOjE1NjQ3MzAwNzksImV4cCI6MTAwMTU2NDczMDA3OH0.YPt-XeLnjV-_1ITaXGY2FhxmCe4NvXuRnRB8OMCfnPo');
// 返回上一页
wx.navigateBack({
delta: 1
})
}
})