1.结算支付
1.1配置分包并跳转到结算页面
随着项目功能的增加,项目体积也随着增大,从而影响小程序的加载速度,影响用户的体验。
因此我们需要将 `结算支付` 功能配置成一个分包,
当用户在访问设置页面时,还预先加载 `结算支付` 所在的分包
`➡️ app.json`
```json
"subPackages": [
{
"root": "modules/settingModule",
"name": "settingModule",
"pages": [
"pages/address/add/index",
"pages/address/list/index",
"pages/profile/profile"
]
},
{
"root": "modules/goodModule",
"name": "goodModule",
"pages": ["pages/goods/list/list", "pages/goods/detail/detail"]
},
+ {
+ "root": "modules/orderPayModule",
+ "name": "orderPayModule",
+ "pages": [
+ "pages/order/detail/detail",
+ "pages/order/list/list"
+ ]
+ }
],
"preloadRule": {
"pages/settings/settings": {
"network": "all",
"packages": ["settingModule"]
},
"pages/category/category": {
"network": "all",
"packages": ["goodModule"]
},
+ "pages/cart/cart": {
+ "network": "all",
+ "packages": ["orderPayModule"]
+ }
}
```
`➡️ pages/cart/cart.js`
```js
// 跳转到订单结算页面
toOrder() {
if (this.data.totalPrice === 0) {
wx.toast({
title: '请选择需要购买的商品'
})
return
}
// 跳转到订单的结算页面
wx.navigateTo({
url: '/modules/orderPayModule/pages/order/detail/detail'
})
}
```
`➡️ pages/cart/cart.wxml`
```html
<van-submit-bar
wx:if="{{ cartList.length }}"
price="{{ totalPrice * 100 }}"
button-text="去结算"
tip="{{ true }}"
+ bindsubmit="toOrder"
>
<van-checkbox
value="{{ selectAllStatus }}"
checked-color="#FA4126"
bindchange="selectAllStatus"
>
全选
</van-checkbox>
</van-submit-bar>
```
1.2封装结算支付的接口 API
为了方便后续进行结算支付模块的开发,我们在这一节将结算支付所有的接口封装成接口 API 函数
`➡️ /api/orderpay.js`
```js
import http from '@/utils/http'
/**
* @description 获取订单详情
* @returns Promise
*/
export const reqOrderInfo = () => {
return http.get('/order/trade')
}
/**
* @description 获取订单列表
* @param {*} page 页码
* @param {*} limit 每页展示的条数
* @returns Promise
*/
export const reqOrderList = (page, limit) => {
return http.get(`/order/order/${page}/${limit}`)
}
/**
* @description 获取订单收货地址
* @returns Promise
*/
export const reqOrderAddress = () => {
return http.get('/userAddress/getOrderAddress')
}
/**
* @description 获取立即购买商品的详情信息
* @param { Object } params { goodsId: 商品 Id, blessing:祝福语 }
* @returns Promise
*/
export const reqBuyNowGoods = ({ goodsId, ...data }) => {
return http.get(`/order/buy/${goodsId}`, data)
}
/**
* @description 提交订单
* @returns Promise
*/
export const reqSubmitOrder = () => {
return http.post('/order/submitOrder')
}
/**
* @description 获取微信预支付信息
* @param {*} orderNo 订单 ID
* @returns Promise
*/
export const reqPreBuyInfo = (orderNo) => {
return http.get(`/webChat/createJsapi/${orderNo}`)
}
/**
* @description 微信支付状态查询
* @param {*} orderNo
* @returns Promise
*/
export const reqPayStatus = (orderNo) => {
return http.get(`/webChat/queryPayStatus/${orderNo}`)
}
```
1.3商品结算-获取收货地址

`➡️ /pages/order/detail/index.js`
```js
import { getTradeAddress } from '../../../api/order'
Page({
data: {
// coding...
+ orderAddress: {} // 收货地址
},
+ // 获取收货地址
+ async getAddress() {
+ const { data: orderAddress } = await reqOrderAddress()
+
+ this.setData({
+ orderAddress
+ })
+ },
+ // 页面展示时触发的钩子函数
+ onShow() {
+ this.getAddress()
+ }
})
```
`➡️ /pages/order/detail/index.wxml`
```html
<!--pages/order/index.wxml-->
<view class="container order">
<view class="address-card">
<!-- 添加收货地址 -->
<view wx:if="{{ !tradeAddress.id }}" class="add-address" bindtap="toAddress">
<van-icon size="22px" name="add" />
<view>添加收货地址</view>
</view>
<view wx:else class="order-address flex">
<view class="address-content">
<view class="title">{{ tradeAddress.fullAddress }}</view>
<view class="info flex">
<text>{{ tradeAddress.name }}</text>
<text>{{ tradeAddress.phone }}</text>
</view>
</view>
<view class="select-address">
<navigator class="navigator" url="/modules/settingModule/pages/address/list/index">
<van-icon color="#bbb" name="arrow" size="22px" />
</navigator>
</view>
</view>
<view class="top-line"></view>
</view>
<view class="order-info">
<!-- coding... -->
</view>
</view>
```
1.4商品结算-更新收货地址功能

`➡️ app.js`
```js
App({
+ // 定义全局共享的数据
+ globalData: {
+ address: {}
+ }
// coding...
})
```
`➡️ /pages/address/list/index.html`
```html
<!-- 每一个收货地址 -->
<view
class="info"
+ bindtap="changeAddress"
+ data-id="{{ item.id }}"
>
<view class="user-info">
<text>{{ item.name }}</text>
<text>{{ item.phone }}</text>
<text wx:if="{{ item.isDefault === 1 }}" class="default-tag">默认</text>
</view>
<view class="address-info"> {{ item.fullAddress }} </view>
</view>
```
`➡️ /pages/address/list/index.js`
```js
// 导入接口 API 函数
import { reqAddressList, reqDelAddress } from '@/api/address'
import { swipeCellBehavior } from '@/behaviors/swipeCell'
+ // 获取全局的应用实例
+ const app = getApp()
Page({
// coding...
+ // 切换收货地址
+ changeAddress(event) {
+ // 判断是否是从订单结算页面进入
+ if (this.flag !== '1') return
+
+ // 获取到点击的收货地址 id
+ const addressId = event.currentTarget.dataset.id
+ // 从收货地址列表中获取到获取到点击的收货地址详细信息
+ const address = this.data.addressList.find((item) => item.id === addressId)
+
+ // 如果获取成功,将数据存储到 globalData 中
+ if (address) {
+ app.globalData.address = address
+ wx.navigateBack()
+ }
+ },
+ onLoad(options) {
+ this.flag = options.flag
+ }
})
```
`➡️ /pages/order/detail/index.wxml`
```html
<view class="select-address">
<navigator
class="navigator"
+ url="/modules/settingModule/pages/address/list/index?flag=1"
>
<van-icon color="#bbb" name="arrow" size="22px" />
</navigator>
</view>
```
`➡️ /pages/order/detail/index.js`
```js
// 获取订单页面的收货地址
async getAddress() {
+ // 如果 globalData 存在收货地址,取出收货地址
+ if (app.globalData.address.id) {
+ this.setData({
+ orderAddress: app.globalData.address
+ })
+
+ // 在赋值以后需要将收货地址清空
+ app.globalData.address = {}
+
+ return
+ }
// 如果 globalData 中不存在收货地址,获取收货地址渲染即可
const { data: orderAddress } = await reqOrderAddress()
this.setData({
orderAddress
})
},
```
1.5商品结算-获取订单详情数据

`➡️ /pages/order/detail/index.js`
```js
+ import { reqOrderAddress, reqOrderInfo } from '@/api/orderpay'
Page({
data: {
// coding...
orderAddress: {}, // 收货地址
+ orderInfo: {}, // 订单商品详情
},
+ // 获取订单详情
+ async getOrderInfo() {
+ const { data: orderInfo } = await reqOrderInfo()
+
+ // 判断是否存在祝福语
+ // 如果需要购买多个商品,挑选第一个填写了祝福语的商品进行赋值
+ const orderGoods = orderInfo.cartVoList.find((item) => item.blessing !== '')
+
+ this.setData({
+ orderInfo,
+ blessing: orderGoods && orderGoods.blessing
+ })
+ },
// 在页面展示的时候进行触发
onShow() {
// 获取收货地址
this.getAddress()
+ // 获取订单结算页面的商品信息
+ this.getOrderInfo()
},
})
```
`➡️ /pages/order/detail/index.wxml`
```html
<!--pages/order/index.wxml-->
<view class="container order">
<view class="address-card">
<!-- 添加收货地址 -->
<!-- coding... -->
</view>
<view class="goods-wraper">
<!-- 商品清单 -->
<view class="goods-list">
+ <view class="goods-item flex" wx:for="{{ tradeInfo.cartVoList }}" wx:key="goodsId">
<view class="img">
+ <image src="{{ item.imageUrl }}" />
</view>
<view class="content">
+ <view class="goods-title">{{ item.name }}</view>
<view class="goods-price">
+ <view class="price"> ¥ {{ item.price }}</view>
+ <view>x {{ item.count }}</view>
</view>
</view>
</view>
</view>
</view>
<view class="payment">
<!-- 支付方式 -->
<view class="time-wraper flex">
<image src="/static/images/payment_wxzf.png" />
<view class="title">支付方式</view>
<van-checkbox value="{{true}}"></van-checkbox>
</view>
</view>
<!-- 支付区域 -->
<view class="footer flex">
+ <view class="left"> ¥ {{ tradeInfo.totalAmount }} </view>
<viwe class="right">结算</viwe>
</view>
<!-- 日期选择弹框 -->
<van-popup show="{{ show }}" round position="bottom" custom-style="height: 50%" bind:close="onClose">
<van-datetime-picker type="date" min-date="{{ minDate }}" model:value="{{ currentDate }}" bind:confirm="onConfirmTimerPicker" bind:cancel="onCancelTimePicker" />
</van-popup>
</view>
```
1.6商品结算-获取立即购买数据

`➡️ /pages/order/detail/index.js`
```js
import {
reqOrderAddress,
reqOrderInfo,
+ reqBuyNowGoods
} from '@/api/orderpay'
Page({
// 获取订单详情
async getOrderInfo() {
+ // 从 data 中结构数据
+ const { goodsId, blessing } = this.data
+ // 判断是否存在商品 id,
// 如果存在调用立即购买商品详情的接口
// 不存在调用获取订单详情数据接口
+ const { data: orderInfo } = goodsId
? await reqBuyNowGoods({ goodsId, blessing })
: await reqOrderInfo()
// 判断是否存在祝福语
// 如果需要购买多个商品,挑选第一个填写了祝福语的商品进行赋值
const orderGoods = orderInfo.cartVoList.find((item) => item.blessing !== '')
this.setData({
orderInfo,
orderGoods && orderGoods.blessing
})
}
+ // 接收立即购买传递的参数
+ onLoad (options) {
+ this.setData({
+ ...options
+ })
+ },
// 在页面展示的时候进行触发
onShow() {
// 获取收货地址
this.getAddress()
// 获取订单结算页面的商品信息
this.getOrderInfo()
}
})
```
1.7商品结算-收集送达时间

`➡️ /pages/order/detail/index.js`
```js
import { formatTime } from '../../../utils/formatTime.js'
Page({
// coding...
// 期望送达日期确定按钮
onConfirmTimerPicker(event) {
// 使用 new Date 将时间戳转换成 JS 中的日期对象
const time = formatTime(new Date(event.detail))
// 将转换以后的时间赋值给送到时间
this.setData({
show: false,
deliveryDate: time
})
}
// coding...
}
```
1.8商品结算-表单数据验证
使用 `async-validator` 对代码进行验证
-
收货地址不能为空
-
订购人姓名不能为空,且不能输入特殊字符
-
订购人手机号不能为空,且输入的手机号必须合法
-
送达日期不能为空
jsimport { reqOrderAddress, reqOrderInfo, reqBuyNowGoods } from '@/api/orderpay' // 导入 async-validator 对参数进行验证 import Schema from 'async-validator' // 导入格式化时间的方法 import { formatTime } from '@/utils/formatTime' // 获取应用实例 const app = getApp() Page({ data: { buyName: '', // 订购人姓名 buyPhone: '', // 订购人手机号 deliveryDate: '', // 期望送达日期 blessing: '', // 祝福语 show: false, // 期望送达日期弹框 orderAddress: {}, // 收货地址 orderInfo: {}, // 订单商品详情 minDate: new Date().getTime(), currentDate: new Date().getTime() }, async submitOrder() { // 从 data 中结构数据 const { buyName, buyPhone, deliveryDate, blessing, orderInfo, orderAddress } = this.data // 组织请求参数 const params = { buyName, buyPhone, deliveryDate, remarks: blessing, cartList: orderInfo.cartVoList, userAddressId: orderAddress.id } // 对请求参数进项验证 const { valid } = await this.validatorPerson(params) // 打印验证结果 console.log(valid) }, // 对新增收货地址请求参数进行验证 validatorPerson(params) { // 验证收货人,是否只包含大小写字母、数字和中文字符 const nameRegExp = '^[a-zA-Z\\d\\u4e00-\\u9fa5]+$' // 验证手机号,是否符合中国大陆手机号码的格式 const phoneReg = '^1(?:3\\d|4[4-9]|5[0-35-9]|6[67]|7[0-8]|8\\d|9\\d)\\d{8}$' // 创建验证规则 const rules = { userAddressId: [{ required: true, message: '请选择收货地址' }], buyName: [ { required: true, message: '请输入收货人姓名' }, { pattern: nameRegExp, message: '收货人姓名不合法' } ], buyPhone: [ { required: true, message: '请输入收货人手机号' }, { pattern: phoneReg, message: '收货人手机号不合法' } ], deliveryDate: { required: true, message: '请选择送达时间' } } // 传入验证规则进行实例化 const validator = new Schema(rules) // 调用实例方法对请求参数进行验证 // 注意:我们希望将验证结果通过 Promise 的形式返回给函数的调用者 return new Promise((resolve) => { validator.validate(params, (errors) => { if (errors) { // 如果验证失败,需要给用户进行提示 wx.toast({ title: errors[0].message }) // 如果属性值是 false,说明验证失败 resolve({ valid: false }) } else { // 如果属性值是 true,说明验证成功 resolve({ valid: true }) } }) }) }, // coding.... })
1.9小程序支付-小程序支付流程
**小程序支付图示:**
<img src="http://8.131.91.46:6677/mina/floor/小程序支付流程.png" style="zoom:80%; border:1px solid #ccc" />
**前端需要做的事情:**
-
`生成平台订单`:前端调用接口,向后端传递需要购买的商品信息、收货人信息,[后端生成平台订单,返回订单编号]
-
`获取预付单信息`:将订单编号发送给后端后, [后端向微信服务器获取预付单信息,后端会将微信服务器返回的预付单信息进行加密,然后将加密以后的预付单信息返回给前端]
-
`发起微信支付`:前端调用 wx.requestPayment() 发起微信支付
-
`查询支付状态`:调用接口查询支付状态
1.10小程序支付-创建平台订单
**思路分析:**
用户在完成选购流程,确认商品信息、订购人、收货人等信息无误后,
用户需要点击提交订单按钮,开始进行下单支付,这时候需要先创建平台订单。
**实现步骤:**
-
在提交订单的事件处理函数中调用封装的接口 API 函数
-
在接口调用成功以后,将服务器响应的订单编码挂载到页面实例上。
➡️ /pages/order/detail/index.jsjsimport { reqOrderAddress, reqOrderInfo, reqBuyNowGoods, + reqSubmitOrder } from '@/api/orderpay' Page({ // coding... // 提交订单 // 处理提交订单 async submitOrder() { // 需要从 data 中解构数据 const { buyName, buyPhone, deliveryDate, blessing, orderAddress, orderInfo } = this.data // 需要根据接口要求组织请求参数 const params = { buyName, buyPhone, cartList: orderInfo.cartVoList, deliveryDate, remarks: blessing, userAddressId: orderAddress.id } // 对请求参数进行验证 const { valid } = await this.validatorPerson(params) + // 如果验证失败,直接 return,不执行后续的逻辑处理 + if (!valid) return + + // 调用接口,创建平台订单 + const res = await reqSubmitOrder(params) + + // 在平台订单创建成功以后,将订单编号挂载到页面实例上 + if (res.code === 200) { + // 将订单编号挂载到页面实例上 + this.orderNo = res.data + } } // coding... })
1.11小程序支付-获取预付单信息
**思路分析:**
将订单编号发送给公司的后端,公司的后端会从数据库找到对应订单的信息。
然后调用微信服务器的 下单接口 进行创建订单,订单创建成功以后,微信服务器会给公司后端返回预付单信息。
公司后端对返回的预付单信息进行加密,返回给小程序客户端。
这一步,咱们需要做的就是:订单编号发送给公司的后端,其他逻辑时后端来完成的。
> 📌:注意事项:
> 小程序支付后面的代码,大伙在实现的时候,会出现异常。
> 这是因为没有小程序的开发权限,以后在实际开发中,只需要参考当前流程进行开发即可
`➡️ /pages/order/detail/index.js`
```js
Page({
// 处理提交订单
async submitOrder() {
// 需要从 data 中解构数据
const {
buyName,
buyPhone,
deliveryDate,
blessing,
orderAddress,
orderInfo
} = this.data
// 需要根据接口要求组织请求参数
const params = {
buyName,
buyPhone,
cartList: orderInfo.cartVoList,
deliveryDate,
remarks: blessing,
userAddressId: orderAddress.id
}
// 对请求参数进行验证
const { valid } = await this.validatorPerson(params)
// 如果请求参数验证失败,直接 return ,不执行后续的逻辑
if (!valid) return
// 调用接口,创建平台订单
const res = await reqSubmitOrder(params)
if (res.code === 200) {
// 在平台订单创建成功以后,需要将服务器、后端返回的订单编号挂载到页面实例上
this.orderNo = res.data
+ // 获取预付单信息、支付参数
+ this.advancePay()
}
},
+ // 获取预付单信息、支付参数
+ async advancePay() {
+ // 调用接口,获取预付单信息、支付参数
+ const payParams = await reqPrePayInfo(this.orderNo)
+
+ if (payParams.code === 200) {
+ console.log(res.data)
+ }
+ },
})
```
1.12小程序支付-发起微信支付
**知识点:**
小程序客户端在接收支付参数后,调用 `wx.requestPayment()` 发起微信支付,
唤醒支付弹窗,用户开输入支付密码或者进行指纹等操作,微信服务器会进行验证,如果验证成功,就会发起支付。
然后会将支付结果返回给公司后端,也会返回给 `wx.requestPayment()`
并且会微信通知用户支付结果
`➡️ /pages/order/detail/index.js`
```js
// 获取预付单信息、支付参数
async advancePay() {
try {
const payParams = await reqPrePayInfo(this.orderNo)
if (payParams.code === 200) {
// 进行微信支付
const payInfo = await wx.requestPayment(payParams.data)
console.log(payInfo)
}
}
catch {
wx.toast({ title: '支付遇到问题,请联系客服', icon: 'error' })
}
}
```
1.13小程序支付-支付状态查询
**思路分析:**
通过调用后端接口获取支付状态,如果支付成功,需要给用户提示,同时跳转到订单列表页面。
公司后端开始向微信服务器发送请求,查询支付结果
公司服务器会将微信服务器返回的支付结果,返回到客户端
客户端根据查询结果跳转到订单列表页面
`➡️ /pages/order/detail/index.js`
```js
// 获取预付单信息、支付参数
async advancePay() {
try {
const payParams = await reqPrePayInfo(this.orderNo)
if (payParams.code === 200) {
// payParams.data 就是获取的支付参数
// 调用 wx.requestPayment 发起微信支付
const payInfo = await wx.requestPayment(payParams.data)
// 获取支付结果
if (payInfo.errMsg === 'requestPayment:ok') {
// 查询订单的支付状态
const payStatus = await reqPayStatus(this.orderNo)
if (payStatus.code === 200) {
wx.redirectTo({
url: '/pages/order/list/index',
success: () => {
wx.toast({
title: '支付成功',
icon: 'success
})
}
})
}
}
}
} catch (error) {
wx.toast({
title: '支付失败,请联系客服',
icon: 'error'
})
}
},
```
2.订单列表
2.1封装订单列表接口 `API`
为了方便后续进行商品管理模块的开发,我们在这一节将商品管理所有的接口封装成接口 API 函数
`➡️ api/orderpay.js`
```js
/**
* @description 获取订单列表
* @returns Promise
*/
export const reqOrderList = (page, limit) => {
return http.get(`/order/order/${page}/${limit}`)
}
```
2.2获取订单列表数据并渲染
**思路分析:**
当用户从个人中心页面点击进入订单中心的时候,就需要获取到订单中心的数据。
在页面调用 `API` 函数获取订单列表的数据,
在获取到数据以后,使用后端返回的数据对页面进行渲染
`➡️ modules/orderPayModule/pages/order/list/list.js`
```js
+ // 导入封装的接口 API 函数
+ import { reqOrderList } from '@/api/orderpay'
Page({
// 页面的初始数据
data: {
orderList: [1, 2, 3], // 订单列表
+ page: 1, // 页码
+ limit: 10, // 每页展示的条数
+ total: 0 // 订单列表总条数
},
+ // 获取订单列表
+ async getOrderList() {
+ // 解构获取数据
+ const { page, limit } = this.data
+ // 调用接口获取订单列表数据
+ const res = await reqOrderList(page, limit)
+
+ if (res.code === 200) {
+ this.setData({
+ orderList: res.data.records,
+ total: res.data.total
+ })
+ }
+ },
+ // 生命周期函数--监听页面加载
+ onLoad() {
+ this.getOrderList()
+ }
})
```
`➡️ modules/orderPayModule/pages/order/list/list.wxml`
```html
<!--pages/order/list/index.wxml-->
<view class="order-container container">
+ <view class="order-list" wx:if="{{ orderList.length > 0 }}">
+ <view class="order-item" wx:for="{{ orderList }}" wx:key="index">
+ <view class="order-item-header list-flex">
<view class="orderno">订单号<text class="no">{{ orderList.orderNo }}</text></view>
+ <view class="order-status {{ item.orderStatus === 1 ? 'order-active' : '' }}">
+ {{ item.orderStatus === 1 ? '已支付' : '未支付'}}
+ </view>
</view>
<view
class="goods-item list-flex"
+ wx:for="{{ item.orderDetailList }}"
+ wx:key="id"
+ wx:for-item="goods"
+ wx:for-index="goodsIndex"
>
<view class="left">
+ <image src="{{ goods.imageUrl }}" mode="widthFix" class="img" />
</view>
<view class="mid">
+ <view class="goods-name">{{ goods.name }}</view>
+ <view class="goods-blessing">{{ goods.blessing }}</view>
</view>
<view class="right">
+ <view class="goods-price">¥{{ goods.price }}</view>
+ <view class="goods-count">x{{ goods.count }}</view>
</view>
</view>
<view class="order-item-footer">
<view class="total-amount list-flex">
<text class="text">实付</text>
+ <text class="price"><text>¥</text>{{ item.totalAmount }}</text>
</view>
</view>
</view>
</view>
<van-empty wx:else description="还没有购买商品,快去购买吧~" />
</view>
```
2.3订单列表上拉加载更多
**思路分析:**
当用户进行了上拉操作时,需要在 `.js` 文件中声明 `onReachBottom` 方法,用来监听页面的上拉触底行为
当用户上拉时,需要对 `page` 参数进行加 1 即可,
当参数发生改变后,需要重新发送请求,拿最新的 `page` 向服务器要数据
在下一页的商品数据返回以后,需要将下一页的数据和之前的数据进行合并
`➡️ modules/orderPayModule/pages/order/list/list.js`
```js
// 导入封装的接口 API 函数
import { reqOrderList } from '@/api/orderpay'
Page({
// 页面的初始数据
data: {
orderList: [1, 2, 3], // 订单列表
page: 1, // 页码
limit: 10, // 每页展示的条数
total: 0 // 订单列表总条数
},
// 获取订单列表
async getOrderList() {
// 解构获取数据
const { page, limit } = this.data
// 调用接口获取订单列表数据
const res = await reqOrderList(page, limit)
if (res.code === 200) {
this.setData({
+ orderList: [...this.data.orderList, ...res.data.records],
total: res.data.total
})
}
},
+ // 页面上拉触底事件的处理函数
+ onReachBottom() {
+ // 解构数据
+ const { page } = this.data
+
+ // 更新 page
+ this.setData({
+ page: page + 1
+ })
+
+ // 重新发送请求
+ this.getOrderList()
+ },
// 生命周期函数--监听页面加载
onLoad() {
this.getOrderList()
}
})
```
2.4判断数据是否加载完毕
**思路分析:**
如何判断数据是否加载完成 ❓
可以使用后端返回的 `total` 和 `goodsList` 进行对比,如果 total 大于 `goodsList` ,说明订单中心数据没有加载完,可以继续上拉加载更多。
目前还没有接收 `total`,需要先将后台返回的 total 进行赋值到 data 中,然后使用 `onReachBottom` 中进行判断
```js
// 页面上拉触底事件的处理函数
onReachBottom() {
+ // 解构数据
+ const { page, total, orderList } = this.data
+
+ // 数据总条数 和 订单列表长度进行对比
+ if (total === orderList.length) {
+ return wx.toast({ title: '数据加载完毕' })
+ }
// 更新 page
this.setData({
page: page + 1
})
// 重新发送请求
this.getOrderList()
}
```
2.5节流阀进行列表节流
在用户网速很慢的情况下,如果用户在距离底部来回的进行多次滑动,可能会发送一些无意义的请求、造成请求浪费的情况,因此需要给上拉加载添加节流功能。
我们使用节流阀来给订单列表添加节流功能。
在 `data` 中定义节流阀状态 `isLoading`,默认值是 `false`。
在请求发送之前,将 `isLoading` 设置为 `true`,表示请求正在发送。
在请求结束以后,将 `isLoading` 设置为 `false`,表示请求已经完成。
在 `onReachBottom` 事件监听函数中,对 `isLoading` 进行判断,如果数据正在请求中,不请求下一页的数据。
`➡️ modules/orderPayModule/pages/order/list/list.js`
```js
// 导入封装的接口 API 函数
import { reqOrderList } from '@/api/orderpay'
Page({
// 页面的初始数据
data: {
orderList: [1, 2, 3], // 订单列表
page: 1, // 页码
limit: 10, // 每页展示的条数
total: 0, // 订单列表总条数
+ isLoading: false // 判断数据是否记载完毕
},
// 获取订单列表
async getOrderList() {
// 解构获取数据
const { page, limit } = this.data
+ // 数据正在请求中
+ this.data.isLoading = true
// 调用接口获取订单列表数据
const res = await reqOrderList(page, limit)
+ // 数据加载完毕
+ this.data.isLoading = false
if (res.code === 200) {
this.setData({
orderList: [...this.data.orderList, ...res.data.records],
total: res.data.total
})
}
},
// 页面上拉触底事件的处理函数
onReachBottom() {
+ // 解构数据
+ const { page, total, orderList, isLoading } = this.data
+ // 判断是否加载完毕,如果 isLoading 等于 true
+ // 说明数据还没有加载完毕,不加载下一页数据
+ if (isLoading) return
// 数据总条数 和 订单列表长度进行对比
if (total === orderList.length) {
return wx.toast({ title: '数据加载完毕' })
}
// 更新 page
this.setData({
page: page + 1
})
// 重新发送请求
this.getOrderList()
},
// 生命周期函数--监听页面加载
onLoad() {
this.getOrderList()
}
})
```
3. 代码优化
3.1分享功能
**思路分析:**
目前小程序页面都没有配置分享功能,需要给小程序页面设置分享功能。
但是并不是所有页面都需要设置分享功能,
具体哪些页面需要设置分享功能,可以和产品经理进行协商。
-
首页
-
商品列表
-
商品详情
js// 转发功能 onShareAppMessage() { return { title: '所有的怦然心动,都是你', path: '/pages/index/index', imageUrl: '../../assets/images/love.jpg' } }, // 转发到朋友圈功能 onShareTimeline() {}
3.2优化-分包调整
**思路分析:**
-
将 [设置页面] 配置到 [设置模块分包],在访问个人中心页面时,提前预下载 [设置模块分包]
-
进入订单结算页面时,提前预下载 [设置模块分包]
➡️ app.jsonjson{ "subPackages": [ { "root": "modules/settingModule", "name": "settingModule", "pages": [ + "pages/settings/settings", "pages/address/add/index", "pages/address/list/index", "pages/profile/profile" ] }, { "root": "modules/goodModule", "name": "goodModule", "pages": ["pages/goods/list/list", "pages/goods/detail/detail"] }, { "root": "modules/orderPayModule", "name": "orderPayModule", "pages": ["pages/order/detail/detail", "pages/order/list/list"] } ], "preloadRule": { + "pages/my/my": { "network": "all", "packages": ["settingModule"] }, + "modules/orderPayModule/pages/order/detail/detail": { + "network": "all", + "packages": ["settingModule"] + }, "pages/category/category": { "network": "all", "packages": ["goodModule"] }, "pages/cart/cart": { "network": "all", "packages": ["orderPayModule"] } }, }
3.3优化-关键按钮添加防抖函数
**思路分析:**
为了防止用户频繁点击按钮而导致的重复提交或者多次请求的问题,
我们需要给关键按钮添加防抖函数,这里可以使用 `licia` 提供的防抖函数
```js
import { debounce } from 'miniprogram-licia'
```
-
登录按钮
-
提交订单
jsimport { debounce } from 'miniprogram-licia' debounce(function () { // coding... }, 500)
3.4优化-代码质量检测
如何使用微信开发者工具进行代码质量检测
<img src="http://8.131.91.46:6677/mina/floor/代码质量检测.png" style="zoom: 56%;" />
代码质量检测标准:
<img src="http://8.131.91.46:6677/mina/floor/代码质量检测标准.png" style="zoom:80%;" />