1.分类页面
1.代码结构
<view>
<view class="category-container">
<!-- 左侧的滚动视图区域 -->
<scroll-view class="category-left-view" scroll-y>
<!-- 一级分类 -->
<view class="left-view-item {{ activeIndex === index ? 'active' : '' }}" wx:for="{{categoryList}}" wx:key="id"
bindtap="updateActive" data-index="{{ index }}">
{{ item.name}}
</view>
</scroll-view>
<!-- 右侧的滚动视图区域 -->
<scroll-view class="category-right-view" scroll-y>
<!-- 二级分类 -->
<view class="test">
<view wx:for="{{ categoryList[activeIndex].children }}" wx:key="index" class="right-view-item">
<navigator class="navigator" url="/pages/goods/list/list?category2Id={{ item.id }}">
<image class="" src="{{ item.imageUrl}}"></image>
<text class="goods_item_name">{{ item.name }}</text>
</navigator>
</view>
</view>
</scroll-view>
</view>
</view>
2.调用接口获取分类数据
// 导入已经封装好的请求api
import {reqCtegoryData} from '../../api/category'
Page({
data:{
categoryList:[],
// 设置被选择的高亮类
// 默认是第0个
activeIndex:0
},
// 实现一级分类的切换效果
updateActive(event){
// console.log(event);
// 打印点击元素的下标
// console.log(event.currentTarget.dataset);
// 将点击元素的下标结构出来
const {index} = event.currentTarget.dataset;
console.log(index);
this.setData ({
activeIndex:index
})
},
async getCategoryData(){
// 调用接口获取分类数据
const res = await reqCtegoryData()
// 将分类数据打印出来
console.log(res);
this.setData({
categoryList:res.data
})
},
// 监听页面加载
onLoad(){
this.getCategoryData()
}
})
3.分类效果图
2.购物车页面
1.代码
js代码
// pages/cart/component/cart.js
Component({
// 组件的属性列表
properties: {},
// 组件的初始数据
data: {
cartList: [1],
emptyDes: '还没有添加商品,快去添加吧~'
},
// 组件的方法列表
methods: {}
})
{
"component": true,
"styleIsolation": "shared",
"usingComponents": {}
}
html代码
<view>
<!-- 购物车列表结构 -->
<view
wx:if="{{ cartList.length }}"
class="container goods-wrap"
bindtap="onSwipeCellPageTap"
>
<view class="goods-item" wx:for="{{ cartList }}" wx:key="index">
<van-swipe-cell class="goods-swipe" right-width="{{ 65 }}">
<van-cell-group border="{{ false }}">
<view class="goods-info">
<view class="left">
<van-checkbox checked-color="#FA4126" value="{{ checked }}"></van-checkbox>
</view>
<view class="mid">
<image class="img" src="/assets/images/floor-img.jpg" />
</view>
<view class="right">
<view class="title">
腾讯极光盒子4智能网络电视机顶盒6K千兆网络机顶盒4K高分辨率
</view>
<view class="buy">
<view class="price">
<view class="symbol">¥</view>
<view class="num">99.00</view>
</view>
<view class="buy-btn">
<van-stepper value="{{ price }}" />
</view>
</view>
</view>
</view>
</van-cell-group>
<view slot="right" class="van-swipe-cell__right">删除</view>
</van-swipe-cell>
</view>
</view>
<!-- 购物车列表为空展示的结构 -->
<van-empty wx:else description="{{ emptyDes }}">
<navigator url="/pages/index/index">
<van-button round type="danger" class="bottom-button">去购物</van-button>
</navigator>
<navigator url="/pages/login/login">
<van-button round type="danger" class="bottom-button">去登录</van-button>
</navigator>
</van-empty>
<!-- 底部工具栏 -->
<van-submit-bar
wx:if="{{ cartList.length }}"
price="{{ 3050 }}"
button-text="去结算"
tip="{{ true }}"
>
<van-checkbox value="{{ true }}" checked-color="#FA4126"> 全选 </van-checkbox>
</van-submit-bar>
</view>
css代码
// 商品列表样式
.goods-wrap {
padding: 16rpx 16rpx 100rpx 16rpx;
.goods-item {
.goods-swipe {
width: 100%;
.goods-info {
display: flex;
align-items: center;
padding: 24rpx 16rpx;
border-radius: 16rpx;
margin-bottom: 16rpx;
background-color: white;
box-sizing: border-box;
transition: transform 1s cubic-bezier(0.18, 0.89, 0.32, 1) !important;
.left {
/* width: 56px; */
display: flex;
align-items: center;
justify-content: center;
}
.mid {
width: 114px;
height: 125px;
.img {
height: 100%;
}
}
.right {
height: 125px;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
margin-left: 10px;
.title {
flex: 1;
flex-shrink: 0;
font-size: 26rpx;
color: #333;
line-height: 44rpx;
font-weight: 400;
overflow: hidden;
word-break: break-word;
}
.buy {
display: flex;
justify-content: space-between;
.price {
display: flex;
color: #fa4126;
font-size: 36rpx;
.symbol {
font-size: 10px;
margin-right: 2px;
margin-top: 8px;
}
}
}
}
}
.van-swipe-cell__right {
background-color: #fa4126;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
width: 130rpx;
color: #fff;
font-size: 24rpx;
height: 100%;
}
}
}
}
// 提交订单栏样式
.submit-footer {
display: flex;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
background-color: white;
padding: 12px 8px;
align-items: center;
justify-content: space-between;
z-index: 10;
.right {
display: flex;
margin-right: 16px;
align-items: center;
justify-content: center;
}
}
购物车页面总体分析
整体结构上页面主体使用了<view>
标签包裹,其中包含了购物车列表的展示逻辑及底部工具栏。
利用了条件渲染wx:if="{{ cartList.length }}"
来判断购物车列表是否为空,据此展示不同的内容。
在购物车页面的完成上,我结合了数据绑定、条件渲染、列表循环和第三方UI库组件,实现了商品展示、选择、数量调整及结算功能。
2.效果图
3.商品细节页面
1.代码
js代码
// pages/goods/detail/index.js
Page({
// 页面的初始数据
data: {
goodsInfo: {}, // 商品详情
show: false, // 控制加入购物车和立即购买弹框的显示
count: 1, // 商品购买数量,默认是 1
blessing: '' // 祝福语
},
// 加入购物车
handleAddcart() {
this.setData({
show: true
})
},
// 立即购买
handeGotoBuy() {
this.setData({
show: true
})
},
// 点击关闭弹框时触发的回调
onClose() {
this.setData({ show: false })
},
// 监听是否更改了购买数量
onChangeGoodsCount(event) {
console.log(event.detail)
}
})
html代码
<view class="container goods-detail">
<!-- 商品大图 -->
<view class="banner-img">
<image class="img" src="/assets/images/floor-img.jpg" />
</view>
<!-- 商品的基本信息 -->
<view class="content">
<view class="price">
<view class="price-num">¥299</view>
<view class="price-origin-num">¥399</view>
</view>
<view class="title">亲爱的/情人节网红款/19枝亲爱的/情人节网红款</view>
<view class="desc">用最温暖的最有情的心意,用最温暖的最有情的心意</view>
</view>
<!-- 商品的详细信息 -->
<view class="detail">
<image class="img" mode="widthFix" src="/assets/images/floor-img.jpg" />
<image class="img" mode="widthFix" src="/assets/images/floor-img.jpg" />
<image class="img" mode="widthFix" src="/assets/images/floor-img.jpg" />
</view>
<!-- 商品的底部商品导航 -->
<van-goods-action>
<navigator url="/pages/index/index" open-type="switchTab">
<van-goods-action-icon icon="wap-home-o" text="首页" />
</navigator>
<navigator url="/pages/cart/cart" open-type="switchTab">
<van-goods-action-icon icon="cart-o" text="购物车" info="{{ allCount }}" />
</navigator>
<van-goods-action-icon
open-type="contact"
icon="chat-o"
text="客服"
bind:click="onClickIcon"
/>
<van-goods-action-button text="加入购物车" type="warning" bindtap="handleAddcart" />
<van-goods-action-button text="立即购买" bindtap="handeGotoBuy" />
</van-goods-action>
<!-- 加入购物车、立即购买弹框 -->
<!-- show 控制弹框的隐藏和展示 -->
<!-- bind:close 点击关闭弹框时触发的回调 -->
<van-action-sheet show="{{ show }}" sh>
<view class="sheet-wrapper">
<view class="goods-item">
<!-- 需要购买的商品图片 -->
<view class="mid">
<image class="img" src="/assets/images/floor-img.jpg" />
</view>
<!-- 商品基本信息 -->
<view class="right">
<!-- 商品名字 -->
<view class="title"> 亲爱的/情人节网红款/19枝 </view>
<!-- 商品价格 -->
<view class="buy">
<view class="price">
<view class="symbol">¥</view>
<view class="num">100</view>
</view>
<!-- 步进器组件控制购买数量 -->
<view class="buy-btn">
<!-- Stepper 步进器,由增加按钮、减少按钮和输入框组成,控制购买数量 -->
<van-stepper value="{{ count }}" bind:change="onChangeGoodsCount" />
</view>
</view>
</view>
</view>
<!-- 祝福语输入框 -->
<view class="time-wraper">
<view class="title">祝福语</view>
<textarea
model:value="{{ blessing }}"
bindinput="onTextAreaChange"
class="form-textarea"
placeholder="必填,写上您的祝福语,给心爱的他(她)送上你的祝福(请勿填写特殊符号或表情符号)"
name="textarea"
/>
</view>
<!-- 确定按钮 -->
<view class="sheet-footer-btn">
<van-button block type="primary" round> 确定 </van-button>
</view>
</view>
</van-action-sheet>
</view>
css代码
/* pages/goods/detail/index.wxss */
.container {
padding: 0rpx !important;
}
.goods-detail {
margin-bottom: 100px;
}
// 商品大图
.banner-img {
height: 800rpx;
image {
height: 100%;
}
}
// 商品的基本信息
.content {
margin: 0 16rpx;
background: white;
padding: 40rpx;
position: relative;
border-radius: 18rpx;
top: -80px;
height: 170rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
overflow: hidden;
.price {
display: flex;
.price-num {
font-size: 18px;
color: #fa4126;
font-weight: bold;
}
.price-origin-num {
font-size: 12px;
color: #b4babf;
margin-left: 4px;
text-decoration: line-through;
margin-top: 6px;
}
}
.title {
font-size: 16px;
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.desc {
font-size: 12px;
color: #999999;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
// 详细图片
.detail {
margin: -130rpx 16rpx 100rpx;
background: white;
padding: 20rpx 16rpx;
border-radius: 16rpx;
}
// 加入购物车、立即购买弹框
.sheet-wrapper {
padding: 16px;
.sheet-footer-btn {
padding: 16px;
}
}
// 商品详情
.goods-item {
display: flex;
align-items: center;
padding: 0 32rpx 40rpx 0;
.left {
width: 56px;
display: flex;
align-items: center;
justify-content: center;
}
.mid {
width: 114px;
height: 125px;
image {
height: 100%;
}
}
.right {
height: 125px;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
margin-left: 10px;
.title {
flex: 1;
flex-shrink: 0;
font-size: 28rpx;
color: #333;
line-height: 40rpx;
font-weight: 400;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
word-break: break-word;
}
.buy {
display: flex;
justify-content: space-between;
.price {
display: flex;
/* align-items: flex-end; */
color: #fa4126;
font-size: 36rpx;
.symbol {
font-size: 10px;
margin-right: 2px;
margin-top: 8px;
}
}
}
}
}
// 祝福语
.time-wraper {
margin-bottom: 12px;
.title,
.time {
justify-content: space-between;
font-size: 14px;
color: #333333;
}
.form-textarea {
border-radius: 12px;
background-color: #f7f8fa;
padding: 16px 12px;
font-size: 13px;
margin-top: 12px;
width: 94%;
height: 84px;
}
}
页面总体分析
在代码片段中我结合微信小程序的原生能力与Vant Weapp UI库组件,构建一个包含商品展示、操作导航、数量选择、个性化留言等多功能的商品详情页面,实现了良好的用户体验和高效的开发流程。
2.效果图
4.订单页面
1.代码
js代码
// pages/order/list/index.js
Page({
// 页面的初始数据
data: {
orderList: [1, 2, 3]
}
})
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">1679246470200</text></view>
<view class="order-status">已支付</view>
</view>
<view class="goods-item list-flex">
<view class="left">
<image src="/assets/images/floor-img.jpg" mode="widthFix" class="img" />
</view>
<view class="mid">
<view class="goods-name">不变的承诺</view>
<view class="goods-blessing">不变的承诺</view>
</view>
<view class="right">
<view class="goods-price">¥100</view>
<view class="goods-count">x1</view>
</view>
</view>
<view class="order-item-footer">
<view class="total-amount list-flex">
<text class="text">实付</text>
<text class="price"><text>¥</text> 666</text>
</view>
</view>
</view>
</view>
<van-empty wx:else description="还没有购买商品,快去购买吧~" />
</view>
css代码
/* pages/order/list/index.wxss */
.list-flex {
display: flex;
}
.order-item {
margin-top: 16rpx;
padding: 24rpx 32rpx 24rpx;
background-color: white;
border-radius: 14rpx;
&:first-child {
margin: 0rpx;
}
.order-item-header {
align-items: center;
justify-content: space-between;
margin-bottom: 24rpx;
}
}
.orderno {
font-size: 28rpx;
font-weight: normal;
color: #333333;
display: flex;
align-items: center;
line-height: 40rpx;
.no {
margin-left: 6px;
}
}
.order-status {
font-size: 26rpx;
line-height: 40rpx;
}
.order-active {
color: #fa4126;
}
.goods-item {
padding: 16rpx 0;
.left {
width: 176rpx;
height: 176rpx;
background: #333333;
}
.mid {
flex: 1;
margin: 0 12px;
.goods-name {
font-size: 28rpx;
color: #333;
line-height: 40rpx;
font-weight: 400;
}
.goods-blessing {
font-size: 24rpx;
height: 32rpx;
line-height: 32rpx;
color: #999999;
margin: 8rpx 0;
}
}
.right {
.goods-price {
white-space: nowrap;
color: #fa4126;
font-size: 24rpx;
line-height: 48rpx;
}
.goods-count {
white-space: nowrap;
order: 4;
text-align: right;
font-size: 24rpx;
color: #999;
margin: 20rpx 0 0 auto;
}
}
}
.order-item-footer {
.total-amount {
justify-content: flex-end;
align-items: center;
}
.text {
font-size: 28rpx;
line-height: 40rpx;
color: #333333;
margin-right: 4px;
}
.price {
font-size: 32rpx;
color: #fa4126;
font-weight: bold;
text {
font-weight: normal;
}
}
}
页面总体分析
这段代码是一个典型的订单列表展示页面,我利用条件渲染和列表循环展示了订单信息,同时通过Vant Weapp的组件增强了页面的实用性和美观度。页面设计考虑到了用户体验,既展现了必要的订单信息,也提供了友好的空状态提示,引导用户进行下一步操作。
2.效果图
5.通用模块的封装
1.1消息模块的封装
1.消息弹出框
App({
//页面显示生命周期函数,每打开页面就会调用一次
onShow(){
wx.showToast({
title: '消息提示框',
// 提示图标:默认成功(一个对勾)
// error:(失败) loading(加载) none(不显示图标)
icon:'success',
duration:2000,
// 是否显示透明蒙层
mask:true
}
})
})
2.封装模块
1.在utils文件夹中新建一个extendApI.js文件,
2.创建⼀个 toast ⽅法对 wx.showToast() ⽅法进⾏封装,
3.使用箭头函数;
// 普通函数
// function name(params){}
// 箭头函数
// name => (参数) {函数体}
// toast = ( { 默认参数 } = {实际参数}) => {函数体}
// ()里为参数
// ()等号左边为函数toast默认的参数
// ()等号右边为调用函数toast传入的参数
const toast = ({title="消息提示框",icon='success',duration=2000,mask=true} = {}) => {
wx.showToast({
title,
icon,
duration,
mask
})
}
// 局部暴露toast方法
export{ toast }
// 全局挂载方法
wx.toast = toast
第一步在appj上创建一个 toast 方法对 wx·&hgwTa&&.()方法进行封装对象中包含 title、icon、dur ation、mask 参数,并给参数设置默认值。
// wx:showToast({
// title: "消息提示框",
// // success(成功)、error(失败)、loading(加载)、none(不显示图标)
// icon:'success',
// duration:2000,
// // 是否显示透明蒙层
// mask:true
// })
duration:是否显出透明蒙层
局部导入又分为不传入参数导入和传入参数导入
不传入参数导入
// 不计入参数的局部导入
// toast()
不传入参数就会一直成功,不传递参数,使用默认参值。
传入参数导入
传入参数的局部导入
// toast({title:'数据加载完毕'})
传入部分参数,覆盖默认的参数
不传入参数的全局挂载方法wx. toast()
传入全局参数的挂载方法
// wx.toast({icon:'none'})
3.在app.js中调用
import { modal } from '/utils/extendApi'
1.2 模块对话框封装
1 // exendApi.js
2
3 // function toast () {}
4
5 // 在调⽤modal⽅法时,可以传递参数,也可以不传递参数。
6 // 如果不传递参数,默认值就是空对象。
7 // 如果传递参数,参数需要时⼀个对象,对象中的属性需要和wx.showModal参数保持⼀致。
8 const modal = (options = {}) => {
9 // 在⽅法内部需要通过Promise返回⽤户的操作
10 // 如果⽤户点击了确认,需要通过resolve返回true
11 // 如果⽤户点击了取消,需要通过resolve返回false
12
13 return new Promise((resolve) => {
14 // 默认的参数
15 const defaultOpt = {
16 title: '提示', // 提示的标题
17 content: '您确定执⾏该操作吗?', // 提示的内容
18 confirmColor: '#f3514f',
19 // 接⼝调⽤结束的回调函数(调⽤成功、失败都会执⾏)
20 complete({ confirm, cancel }) {
21 confirm && console.log('点击了确定')
22 cancel && console.log('点击了取消')
23 }
24 }
25
26 // 通过object.assgin⽅法将参数进⾏合并
27 // 需要使⽤传⼊的参数覆盖默认的参数
28 // 为了不影响默认的参数,需要将合并以后的参数赋值给⼀个空对象
29 const opts = Object.assign({}, defaultOpt, options)
30
31 wx.showModal({32 // 将合并以后的参数通过展开运算符赋值给wx.showModal对象
33 ...opts,
34 complete({ confirm, cancel }) {
35 // 如果⽤户点击了确定,通过 resolve 抛出 true
36 // 如果⽤户点击了取消,通过 resolve 抛出 false
37 confirm && resolve(true)
38 cancel && resolve(false)
39 }
40 })
41 })
42 }
43
44 export { modal }
45
46 wx.modal = modal
47
1 // app.js
2
3 // app.js
4 // import { toast } from './utils/extendApi'
5 import './utils/extendApi'
6
7 App({
8 // ⻚⾯显示⽣命周期函数
9 async onShow() {
10
11 // wx.showModal({
12 // title: '提示', // 提示的标题
13 // content: '您确定执⾏该操作吗?', // 提示的内容
14 // confirmColor: '#f3514f',
15 // // 接⼝调⽤结束的回调函数(调⽤成功、失败都会执⾏)
16 // complete({ confirm, cancel }) {
17 // confirm && console.log('点击了确定')
18 // cancel && console.log('点击了取消')
19 // }
20 // })在⼩程序中,经常需要将⼀些数据存储到本地,⽅便多个⻚⾯的读取使⽤,例如:将⽤户的登录状
态、⽤户的个⼈信息存储到本地。
⼩程序提供了同步、异步两类 API 来实现本地存储操作。例如: wx.setStorageSync 、 wx.setStorage
等⽅法。
21
22 // 不传⼊参数
23 // const res = await wx.modal()
24
25 // 传⼊参数
26 const res = await wx.modal({
27 title:'新的提示',
28 showCancel:false
29 })
30
31 console.log(res);
32
33 }
34
35 })
// 再调用modal方法是,可以传递参数,也可以不传递参数
// 如果不传递参数,默认值就是空对象
// 如果传递参数,参数需要是一个对象,对象中的属性需要和wxwx.showModal参数保持一致
const modal = (options = {}) => {
// 通过new关键字构建一个promise对象
// 在方法内部通过promise返回用户的操作
// resolve为用户点击确认框的结果
return new Promise((resolve) => {
// 用户使用model函数时,使用showModal的默认参数
const defaultOpt = {
title:'提示',
content:'你确定要执行该操作吗',
confirmColor:'#f2514f',
// 接口调用结束后的回调函数
complete({confirm,cancel}){
confirm && console.log('点击了确定');
cancel && console.log('点击了取消');
}
}
// Object.assign()方法用于将对象复制到目标对象
// 通过Object.assign()方法将参数合并
// 如果用户传递进来了options,就会覆盖默认参数
// 第一个空对象参数会被赋值合并后的参数
const opts = Object.assign({},defaultOpt,options)
wx.showModal({
// ...扩展运算符
// 将合并后的参数通过展开运算符赋值给wx.showModal对象。
...opts,
complete({confirm,cancel}){
// 如果用户点击了确认,通过resolve抛出true
confirm && console.log('点击了确定');
// 如果用户点击了取消,通过resolve抛出false
cancel && console.log("点击了取消");
}
})
})
}
// 局部暴露modal方法
export{ modal }
当我们在调用modal方法时,可以传递参数,也可以不传递参数
如果不传递参数,默认值就是空对象如果传递参数,参数需要是一个对象,对象中的属性需要和wx,showModal参数保持一致通过new关键字构建-个promise对象在方法内部通关promise返回用户的操作
resolve为用户点击确认框的结果
日户使用modal函数时,使用showModal的默认参数
Dbiect.assiqn0方法用于将对象复制到目标对象。
通过Obiect.assiqn0方法将参数合并
如果用户传递进来了options,就会覆盖默认参数
局部暴露:先在extendApi.js中暴露modal,然后在appjs中使用import引入modal,最后在onShow()中写入modal0)完成局部暴露
全局暴露:先在extendApijs中完成全局挂载,然后在app,js中的onShow0)中写入wx.modal0)完成全局暴露
1.3封装本地存储 API
我们在 utils ⽬录下新建 storage.js ⽂件 在该⽂件中,封装对本地数据进⾏ 存储、获取、删除、清除的⽅法
// wx.setStorage(option)是微信小程序存储数据的api
// setStorage()是自定义函数
// key 本地存储中的变量名
// value 变量名对应的变量值
// 以同步方法存储数据
export const setStorage = (key,value) => {
try {
wx.setStorageSync(key,value)
}catch (error){
console.log("存储失败");
}
}
// 以同步方法获取数据
export const getStorage = (key) => {
try{
const value = wx.getStorageSync(key)
if(value){
return value
}
}catch (error){
console.log("存储失败");
}
}
// 删除数据
export const removeStorage = (key) => {
try {
wx.removeStorageSync(key)
}catch(e){
console.log("删除失败");
}
}
// 删除全部数据
export const clearStorage = () => {
try{
wx.clearStorageSync()
}catch(e){
console.log("清除失败");
}
}
6.网络请求封装
1.1请求封装-request⽅法
1.request⽅法封装
// 1.使用了微信自带的请求api wx.request
// 2.将wx.request封装到了一个名为request的函数中
// 3.将函数封装到了一个名为wxRequest的类中
// 创建一个WxRequest类
// 通过类的方式进行封装,会让代码更具有复用性
// 也可以方便添加新的属性和方法
class WxRequest{
// 用于创建和初始化类的属性和方法
constructor(){}
// request实例方法接受一个对象类型的参数
request(options){
return new Promise((resolve,reject) => {
wx.request({
// 使用拓展运算符将request函数传来的对象参数展开
...options,
// 当接口调用成功就会触发success回调函数
success:(res) => {
resolve(res)
},
//当接口调用失败时会触发fail回调函数
fail:(err)=>{
reject(err)
}
})
})
}
}
//对wxRequest进行实例化
const instance = new WxRequest()
//将WxRequest实例暴露出去,方便在其他文件中进行使用
export default instance
// 导入在request页面中封装并暴露的instance实例
import instance from '../../utils/http'
// pages/test/test.js
Page({
// 具体阐述按钮点击事件要做什么事情
async handler(){
// 第一种调用方法:通过.then和.catch接受返回的值
// instance
// .request({
// // 请求地址
// url:'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
// // 请求方式
// method:"GET"
// })
// .then((res) => {
// console.log(res);
// })
// .catch((err) => {
// console.log(err);
// })
// 第二种调用方法:通过await和async接受返回的值
// const res = await instance.request({
// url:'/index/findBanner',
// method:"GET"
// })
// 第三种调用方式:通过调用快捷方式接受返回的值
// const res = await instance.get('/index/findBanner')
// 调用并传参
// const res = await instance.get('/index/findBanner',{test:111},
// {timeout:20000})
//当前请求地址是获取购物车数据,需要token才行
const res = await instance.get('/cart/getCartList')
console.log(res);
},
})
/* pages/test/test.wxss */
.box{
display: flex;
// 主轴方向上居中
justify-content: center;
// 副轴方向上居中
align-items: center;
// 将盒子高度设置为页面高度
height: 100vh;
}
<!--pages/test/test.wxml-->
<!-- <text>pages/test/test.wxml</text> -->
<view class="box">
<!-- 设置一个按钮 并给按钮设置一个名为handler的点击事件 点击按钮则会发送请求 -->
<button type="warn" size="mini" plain bindtap="handler">测试发送请求</button>
</view>
1.2请求封装-设置请求参数
1.创建一个WxRequest类,通过类的方式进行封装 会让代码更具有复用性,也可以方便添加新的属性和方法。
2.通过WxRequest来设定默认参数对象,请求基地址,服务器接口地址,请求方式、参数和请求头,设置数据的交互格式并且设置默认超时时间。
3.定义拦截对象包括请求拦截和响应拦截方法,方便在请求或响应之前进行处理。请求拦截器:request,响应拦截器:response
4.创建params为用户传入的请求配置项,使用Object.assign方法合并默认参数以及传递的请求参数,需要传入的参数,会覆盖默认的参数,因此传入的参数放在最后。
5.request需要接受一个对象类型的参数, 拼接完整的请求路径options.url,合并请求参数options ={...this.defaults,...options},在发送请求之前调用请求拦截器options = this.interceptors.request(options)
6. 使用拓展运算符将request函数传来的对象参数展开 ...options, 当接口调用成功就会触发success回调函数。
不管接口成功还是失败,都需要调用响应拦截器;响应拦截器需要接受服务器响应的数据,然后对数据进行逻辑处理,处理好后进行返回;在给响应拦截器传递参数时 需要将请求参数也一起上传;方便进行代码的调式或者其他逻辑处理,所以需要合并数据;然后将合并的参数给响应拦截器。
当接口调用失败时会触发fail回调函数
7.第一个参数:需要合并的目标对象;第二个参数:服务器响应的数据;第三个参数:请求配置以及自定义属性
8.GET POST PUT DELETE四个封装方法
9.对WxRequest进行实例化
10.配置请求拦截器并且发送请求;响应拦截器了解发送前需要做什么
11.将WxRequest实例暴露出去 方便在其他文件中进行使用 export default instance
1.3封装请求快捷⽅法
⽬前已经完成了 request() 请求⽅法的封装,同时处理了请求参数。 每次发送请求时都使⽤ request() ⽅法即可,但是项⽬中的接⼝地址有很多,不是很简洁。所以我们在 request() 基础上封装⼀些快捷⽅法,简化 request() 的调⽤。
// 封装GET方法
get(url,data={},config={}){
return this.request(Object.assign({url,data,method:'GET',config}))
}
// 封装POST实例方法
post(url,data={},config={}){
return this.request(Object.assign({url,data,method:'POST',config}))
}
// 封装PUT方法
put(url,data={},config={}){
return this.request(Object.assign({url,data,method:'PUT',config}))
}
// 封装DELETE方法
delete(url,data={},config={}){
return this.request(Object.assign({url,data,method:'DELETE',config}))
}
// 对类进行实例化
const instance = new WxRequest({
baseURL: 'https://gmall-prod.atguigu.cn/mall-api',
timeout: 15000
})
// 将 WxRequest 实例进⾏暴露出去,⽅便在其他⽂件中进⾏使⽤
export default instance
// 导入在request页面中封装并暴露的instance实例
import instance from '../../utils/http'
// pages/test/test.js
Page({
// 具体阐述按钮点击事件要做什么事情
async handler(){
// 第一种调用方法:通过.then和.catch接受返回的值
// instance
// .request({
// // 请求地址
// url:'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
// // 请求方式
// method:"GET"
// })
// .then((res) => {
// console.log(res);
// })
// .catch((err) => {
// console.log(err);
// })
// 第二种调用方法:通过await和async接受返回的值
// const res = await instance.request({
// url:'/index/findBanner',
// method:"GET"
// })
// 第三种调用方式:通过调用快捷方式接受返回的值
// const res = await instance.get('/index/findBanner')
// 调用并传参
// const res = await instance.get('/index/findBanner',{test:111},
// {timeout:20000})
//当前请求地址是获取购物车数据,需要token才行
const res = await instance.get('/cart/getCartList')
console.log(res);
},
}
1.4 定义请求/响应拦截器
为了⽅便统⼀处理请求参数以及服务器响应结果,为 WxRequest 添加拦截器功能,拦截器包括 请求 拦截器 和 响应拦截器
请求拦截器本质上是在请求之前调⽤的函数,⽤来对请求参数进⾏新增和修改
响应拦截器本质上是在响应之后调⽤的函数,⽤来对响应数据做点什么
// 1.使用了微信自带的请求api wx.request
// 2.将wx.request封装到了一个名为request的函数中
// 3.将函数封装到了一个名为wxRequest的类中
// 创建一个WxRequest类
// 通过类的方式进行封装,会让代码更具有复用性
// 也可以方便添加新的属性和方法
class WxRequest{
// 默认参数对象
defaults = {
// 请求基地址
baseURL:'',
// 服务器接口地址
url:'',
// 请求方式
method:'GET',
// 请求参数
data:null,
// 请求头
header: {
'Content-type': 'application/json' // 设置数据的交互格式
},
// 默认超时时间为一分钟
timeout:100
}
// 定义拦截对象,包括请求拦截和响应拦截,方便在请求或响应之前进行处理
interceptors = {
// 请求拦截
request:(config) => config,
// 响应拦截
response:(response) => response
}
// 用于创建和初始化类的属性和方法
// params为用户传入的请求配置项
constructor(params = {}){
// 使用Object.assign方法合并默认参数以及传递的请求参数
// 需要传入的参数,会覆盖默认的参数,因此传入的参数放在最后
this.defaults = Object.assign({},this.defaults,params)
}
// request实例方法接受一个对象类型方法
request(options){
// 拼接完整的请求路径
options.url = this.defaults.baseURL + options.url
// 合并请求参数
options = {...this.defaults,...options}
// 发送请求之前添加loading
wx.showLoading({})
// 在发送请求之前调用请求拦截器
options = this.interceptors.request(options)
console.log(options);
return new Promise((resolve,reject) => {
wx.request({
// 使用拓展运算符将request函数传来的对象参数展开
...options,
// 当接口调用成功就会触发success回调函数
success:(res) => {
// 不管接口成功还是失败,都需要调用响应拦截器
// 响应拦截器需要接受服务器响应的数据,然后对数据进行逻辑处理,处理好后进行返回
// 在响应拦截器传递参数时,需要将请求参数也一起上传
// 方便进行代码的调试或者其他逻辑处理,所以需要合并参数
// 然后将合并的参数给响应拦截器
// 第一个参数:需要合并的目标对象
// 第二个参数:服务器响应的数据
// 第三个参数:请求配置以及自定义属性
// 不管是请求失败还是请求成功,都会将响应的数据传递给响应拦截器
// 这个时候合并参数时,就需要追加一个属性:isSuccess
// 如果属性值为true说明执行了success回调函数
const mergetRes = Object.assign({},res,{config:options,isSuccess:true})
// resolve(res)
resolve(this.interceptors.response(mergetRes))
},
// 当接口调用失败就会触发fail回调函数
fail:(err) => {
// 如果属性值为false,说明执行了fail回调函数
const mergetErr = Object.assign({},err,{config:options,isSuccess:false})
// reject(err)
reject(this.interceptors.response(mergetErr))
},
// 不管promisse请求是否成功
// 都会执行complete里面的内容
complete:()=>{
// 接口调用完成后隐藏loading
wx.hideLoading()
}
})
})
}
// 封装GET方法
get(url,data={},config={}){
return this.request(Object.assign({url,data,method:'GET',config}))
}
// 封装POST实例方法
post(url,data={},config={}){
return this.request(Object.assign({url,data,method:'POST',config}))
}
// 封装PUT方法
put(url,data={},config={}){
return this.request(Object.assign({url,data,method:'PUT',config}))
}
// 封装DELETE方法
delete(url,data={},config={}){
return this.request(Object.assign({url,data,method:'DELETE',config}))
}
}
export default WxRequest
1.5完善请求/响应拦截器
在响应拦截器,我们需要判断是请求成功,还是请求失败,然后进⾏不同的业务逻辑处理。 例如:请求成功以后将数据简化返回,⽹络出现异常则给⽤户进⾏⽹络异常提示。 ⽬前不管请求成功 (success),还是请求失败(fail),都会执⾏响应拦截器 那么怎么判断是请求成功,还是请求失败呢 ?
1.6使⽤请求/响应拦截器
使⽤响应拦截器: 在使⽤ wx.request 发送⽹络请求时。只要成功接收到服务器返回,⽆论 statusCode 是多少,都会进 ⼊ success 回调。 因此开发者根据业务逻辑对返回值进⾏判断。
11 // 响应拦截器
12 instance.interceptors.response = async (response) => {
13
14 console.log(response);
15
16 // 从response中结构isSuccess
17 // const { isSuccess } = response
18 const { isSuccess, data } = response
1.
2.
3.19
20 // 如果isSuccess为false,说明执⾏了fail回调函数
21 // 这时候说明⽹络异常,需要给⽤户提示⽹络异常
22 if (!isSuccess) {
23 wx.showToast({
24 title: '⽹络异常请重试',
25 icon: 'error'
26 })
27
28 return response
29 }
30
31 // 判断服务器响应的业务状态码
32 switch(data.code){
33
34 // 如果后端返回的业务状态码等于200,说明请求成功,服务器成功响应了数据
35 case 200:
36 // 对服务器响应数据做点什么
37 return data
38
39 // 如果返回的业务状态码等于208,说明没有token,或者token失效
40 // 就需要让⽤户登录或者重新登录
41 case 208:
42 const res = await modal({
43 content:'鉴权失败,请重新登录',
44 showCancel:false // 不显示取消按钮
45 })
46 if(res){
47 // 清除之前失效的token,同时要清除本地存储的全部信息
48 clearStorage()
49 wx.navigateTo({
50 url: '/pages/login/login',
51 })
52 }
53 return Promise.reject(response)
54
55 default:
56 toast({
57 title:'程序出现异常,请联系客服或稍后重试'
58 })
59 return Promise.reject(response)
60 }
61
62 // 对响应数据做点什么
63 // return response
64 // return data
65 }
66
67 // 将 WxRequest 的实例通过模块化的⽅式暴露出去
68 export default instance