慕尚花坊 --- 我的
1. 登录
1. Token
**1. 什么是 Token **
Token 是服务器生成的一串字符串, 用作客户端发起请求的一个身份令牌。当第一次登录成功后, 服务器生成一个 Token 便将次 Token 返回给客户端, 客户端在接收到 Token 后, 会使用某种方式将 Token 保存到本地。以后客户端发起请求, 只需要在请求头上携带这个 Token, 服务器通过验证 Token来确认用户的身份, 而无需再次带上用户名和密码。
2. Token 的交互流程
- 客户端向服务器发起登录请求, 服务端验证用户名与密码
- 验证成功后, 服务端会签发一个
Token, 并将Token发送给客户端 - 客户端收到
Token以后, 将其存储起来, 比如放在localStorage、sessionStorage中 - 客户端每次向服务器请求资源的时候, 需要携带服务器签发的
Token, 服务端收到请求, 然后去验证客户端请求中携带的Token, 如果验证成功, 就向客户端返回请求的数据

2. 实现流程
传统的登录功能, 需要用户先注册, 注册完成后, 使用注册的账号、密码进行登录, 小程序的登录流程比较简单, 小程序可以通过微信提供的登录能力, 便捷的获取微信提供的用户身份标识进行登录, 免去了注册和输入账号密码的步骤, 从而提高了用户体验
官方文档
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
**小程序登录图示: **

3. 集成 Vant Weapp
1. 安装
npm i @vant/weapp
2. 工具 => 构建 Npm
3. 修改 app.json
{
"style": "v2" // 删除此配置项
}
4. 引入组件
pages/login/login.json
{
"usingComponents": {
"van-empty": "@vant/weapp/empty/index",
"van-button": "@vant/weapp/button/index"
}
}
4. 页面构建
pages/login/login.wxml
<van-empty class="empty-image" image="/assets/default.png" description="点击下方的按钮, 授权登录您的账户">
<van-button round type="danger" class="bottom-button">点击授权登录</van-button>
</van-empty>
5. 数据交互
1. 绑定点击事件
pages/login/login.wxml
<van-empty class="empty-image" image="/assets/default.png" description="点击下方的按钮, 授权登录您的账户">
<van-button round type="danger" class="bottom-button" bindtap="login">点击授权登录</van-button>
</van-empty>
2. 获取临时登录凭证,并发送给后端服务器, 得到 token 后将其保存在本地
api/user.js
import http from '../utils/http'
export const reqLoginData = (code) => {
return http.get(`wexin/wxLogin/${code}`)
}
pages/login/login.js
import {
toast
} from '@/utils/extendAPI'
import {
reqLoginData
} from '@/api/user'
import {
setStorage
} from '@/utils/storage'
Page({
// 获取临时登录凭证 Code
login() {
wx.login({
success: async (res) => {
const { code } = res
if (code) {
// code 获取成功后, 传给后端服务器,后端会返回 token 字符串
const res = await reqLoginData(code)
// 将 token 保存在本地
setStorage('token', res.token)
} else {
toast({
title: "授权失败,请重新授权"
})
}
},
})
},
})
3. 每次发送请求时, 携带 token 在请求头中, 发送给服务器
utils/http.js
import WxRequest from './request'
import {
getStorage,
clearStorage
} from './storage'
import {modal, toast} from './extendAPI'
// 实例化 WxRequest,并配置基准地址
const wxr = new WxRequest({
baseURL: 'https://gmall-prod.atguigu.cn/mall-api',
timeout: 15000
})
// 配置请求拦截器
wxr.interceptors.request = (config) => {
// 在发送请求前, 需要先判断本地是否存在访问令牌 token
const token = getStorage('token')
// 如果存在,则需要在请求头中添加该令牌
if (token) {
config.header.token = token
}
return config
}
// 配置响应拦截器
wxr.interceptors.response = async (response) => {
const {
isSuccess,
data
} = response
if (!isSuccess) {
wx.showToast({
title: '网络异常请重试',
icon: 'error'
})
return response
}
// 判断状态码
switch (data.code) {
case 200:
return data
case 208:
const res = await modal({
content: '鉴权失败, 请重新登录',
showCancel: false
})
if (res) {
clearStorage()
wx.navigateTo({
url: '/pages/login/login',
})
}
return Promise.reject(response)
default:
toast({
title: "程序出现异常, 请联系客服或稍后重试"
})
return Promise.reject(response)
}
}
export default wxr
6. token 存储到 store
将 Token 直接存储到本地不方便对数据进行操作: 要先从本地存储取出、修改、保存, 并且 存储到本地的数据不是响应式的, 当本地存储里面的内容发生改变, 页面不会发生改变。这时候就需要将 Token 存储到 Store中,
1. 安装 Mobx, 并构建 工具 => 构建Npm
npm i mobx-miniprogram mobx-miniprogram-bindings
2. 创建 Store 对象
stores/userStore.js
import {
observable,
action
} from 'mobx-miniprogram'
import {
getStorage
} from '@/utils/storage'
export const userStore = observable({
// 定义响应式数据
token: getStorage('token') || '',
// 修改 Token
setToken: action(function (token) {
this.token = token
})
})
pages/login/login.js
import {
toast
} from '@/utils/extendAPI'
import {
reqLoginData
} from '@/api/user'
import {
setStorage
} from '@/utils/storage'
import {
ComponentWithStore
} from 'mobx-miniprogram-bindings'
import {
userStore
} from '@/stores/userStore'
ComponentWithStore({ // 使用 ComponentWithStore() 替换 Page()
data: {
},
storeBindings: {
store: userStore,
fields: ['token'],
actions: ['setToken']
},
methods: { // 将 login 回调函数挪到 methods 对象中
login() {
wx.login({
success: async (res) => {
const {
code
} = res
if (code) {
const res = await reqLoginData(code)
setStorage('token', res.token)
this.setToken(res.token) // 将 token 保存到 store
wx.navigateTo({
url: '/pages/my/my',
})
} else {
toast({
title: "授权失败,请重新授权"
})
}
},
})
},
},
})
2. 用户信息
用户信息可能会在多个页面或组件中使用, 为了方便对用户信息的获取和使用, 需要将用户信息存储到 store
1. 获取用户信息
1. 封装接口 API 函数
api/user.js
import http from '@/utils/http'
/**
* @description 登录
* @param {String} code 临时登录凭证
* @returns Promise
*/
export const reqLoginData = (code) => {
return http.get(`/wexin/wxLogin/${code}`)
}
/**
* @description 获取用户信息
* @returns Promise
*/
export const reqUserInfo = () => {
return http.get('/weixin/getuserInfo')
}
2. 保存用户信息到 本地 和 store
1. 发送请求获取用户信息,并保存在 本地 和 store 中
pages/login/login.js
import {
toast
} from '@/utils/extendAPI'
import {
reqLoginData,
reqUserInfo
} from '@/api/user'
import {
setStorage
} from '@/utils/storage'
import {
ComponentWithStore
} from 'mobx-miniprogram-bindings'
import {
userStore
} from '@/stores/userStore'
ComponentWithStore({
data: {
},
storeBindings: {
store: userStore,
fields: ['token', 'userInfo'], // 绑定 store 中的用户信息
actions: ['setToken', 'setUserInfo']
},
methods: {
login() {
wx.login({
success: async (res) => {
const {
code
} = res
if (code) {
const res = await reqLoginData(code)
setStorage('token', res.token)
this.setToken(res.token)
// 获取用户信息,并保存到 本地 和 store
this.getUserInfo()
wx.navigateTo({
url: '/pages/my/my',
})
} else {
toast({
title: "授权失败,请重新授权"
})
}
},
})
},
// 获取用户信息
async getUserInfo() {
const {data} = await reqUserInfo()
// 将用户信息存储在本地
setStorage('userInfo', data)
// 将用户信息存储在 store
this.setUserInfo(data)
}
}
})
stores/userStore.js
import {
observable,
action
} from 'mobx-miniprogram'
import {
getStorage
} from '@/utils/storage'
export const userStore = observable({
// 定义响应式数据
token: getStorage('token') || '',
userInfo: getStorage('userInfo') || '',
setToken: action(function (token) {
this.token = token
}),
// 修改 用户信息
setUserInfo: action(function (userInfo) {
this.userInfo = userInfo
})
})
3. 页面构建
在获取到用户信息后, 已经将用户信息存储到了 本地 和 Store, 想在页面渲染则需要从 Store 中取出用户数据, 并渲染到页面中。
如果用户没有登录, 展示默认头像, 提示用户登录的文案信息, 不展示设置按钮
如果用户已经登录, 展示用户的头像和昵称, 并且展示设置按钮, 方便用户对收货地址、头像、昵称进行更改
**1. 实现思路: **
- 在个人中心页面导入
ComponentWithStore方法构建页面 - 配置
storeBindings让组件和Store建立关联 - 渲染页面
0. 我的
0. 效果图

1. 构建页面
pages/my/my.wxml
<view class="container">
<!-- 顶部展示图 -->
<view class="top-show">
<image class="img" src="../../assets/swipers/swiper-1.jpg" mode="" />
</view>
<view class="bottom-show">
<!-- 未登录面板 -->
<view class="user-container section">
<image class="empty-image" src="../../assets/default.png" mode="" />
<view class="login-status">
<text>未登录</text>
<text>点击授权登录</text>
</view>
</view>
<!-- 登录面板 -->
<!-- <view class="user-container section">
<image class="empty-image" src="../../assets/default.png" mode="" />
<view class="login-status">
<text>未登录</text>
<text>点击授权登录</text>
</view>
</view> -->
<!-- 订单面板 -->
<view class="order section">
<view class="order-top">
<view>
<text>我的订单</text>
</view>
<navigator url="">
<text>查看更多></text>
</navigator>
</view>
<view class="order-content">
<navigator url="" class="content-item">
<text class="iconfont icon-dingdan"></text>
<text class="title">商品订单</text>
</navigator>
<navigator url="" class="content-item">
<text class="iconfont icon-lipinka"></text>
<text class="title">礼品卡订单</text>
</navigator>
<navigator url="" class="content-item">
<text class="iconfont icon-shouhou"></text>
<text class="title">退款/售后</text>
</navigator>
</view>
</view>
<!-- 关于售前售后服务面板 -->
<view class="after-scale section">
<view class="scale-top">
<text>关于售前售后服务</text>
</view>
<view class="scale-content">
<navigator url="" class="content-item">
<text class="iconfont icon-kefu"></text>
<text>可与小程序客服实时聊天或电话咨询</text>
</navigator>
<navigator url="" class="content-item">
<text class="iconfont icon-shijian"></text>
<text>小程序客服工作时间为 08:30 - 20:30</text>
</navigator>
<navigator url="" class="content-item">
<text class="iconfont icon-gantanhao"></text>
<text>鲜花制作完毕情况下暂不支持退款</text>
</navigator>
<navigator url="" class="content-item">
<text class="iconfont icon-bijijilu"></text>
<text>鲜花可以提前7-15天预定重大节假日不支持定时配送</text>
</navigator>
</view>
</view>
</view>
</view>
paes/my/my.scss
.container {
position: relative;
// overflow: hidden;
.top-show {
.img {
width: 100%;
height: 400rpx;
position: absolute;
z-index: -100;
}
}
.bottom-show {
width: 100%;
position: absolute;
top: 290rpx;
.user-container {
height: 130rpx;
display: flex;
background-color: #efefef;
margin: 0 15rpx;
padding: 20rpx;
border-radius: 25rpx;
.empty-image {
width: 120rpx;
height: 120rpx;
}
.login-status {
display: flex;
flex-direction: column;
justify-content: center;
font-size: 27rpx;
color: #979292;
margin-left: 20rpx;
}
}
.order {
height: 230rpx;
border-radius: 25rpx;
background-color: #efefef;
padding: 20rpx;
margin: 15rpx;
.order-top {
display: flex;
justify-content: space-between;
font-size: 35rpx;
navigator {
text {
color: #bbb8b8;
font-size: 28rpx;
}
}
}
.order-content {
margin-top: 20rpx;
display: flex;
justify-content: space-between;
.content-item {
display: flex;
flex-direction: column;
padding: 20rpx;
.iconfont {
font-size: 80rpx;
margin: 0 auto;
}
.title {
margin-top: 10rpx;
font-size: 28rpx;
}
}
}
}
.after-scale {
height: 437rpx;
background-color: #efefef;
padding: 20rpx;
margin: 15rpx;
.scale-top {
font-size: 34rpx;
font-weight: 600;
}
.scale-content {
margin-top: 30rpx;
.content-item {
font-size: 26rpx;
color: #979292;
margin-bottom: 40rpx;
}
.iconfont {
color: rgb(221, 221, 121);
margin-right: 15rpx;
}
}
}
}
}
1. 设置
pages/setup/setup.wxml
<view class="container">
<view class="item-container">
<navigator class="item" url="../../pages/setup/personal-data/personal-data">
<text>修改个人资料</text>
<text class="right">></text>
</navigator>
<navigator class="item" url="../../pages/setup/receive-address/receive-address">
<text>我的收货地址</text>
<text class="right">></text>
</navigator>
<navigator class="item" url="../../pages/setup/problem-feedback/problem-feedback">
<text>问题反馈</text>
<text class="right">></text>
</navigator>
<navigator class="item" url="../../pages/setup/contact-us/contact-us">
<text>联系我们</text>
<text class="right">></text>
</navigator>
<navigator class="item" url="../../pages/setup/auth-info/auth-info">
<text>授权信息</text>
<text class="right">></text>
</navigator>
</view>
</view>
pages/setup/setup.scss
.container {
width: 100%;
height: 100%;
background-color: #efefef;
.item {
width: 100%;
height: 40rpx;
background-color: white;
margin: 16rpx 20rpx;
padding: 20rpx;
font-size: 28rpx;
font-weight: 500;
display: flex;
justify-content: space-between;
.right {
font-size: 28rpx;
font-weight: 300;
margin-right: 70rpx;
}
}
}
4. 分包加载
1. 分包处理
随着项目功能的增加, 项目体积也随着增大, 从而影响小程序的加载速度, 影响用户的体验, 因此需要将 更新个人资料 和收货地址 功能配置成一个分包, 当用户在访问设置页面时, 还要预先加载 更新个人资料 和 收货地址 所在的分包
在分包后, 通过查看代码依赖检查是否分包完成: 详情 => 基本信息 => 代码依赖分析
1. 新建文件夹来存放分包后的页面: miniprogram/modules/settingModule
app.json
{
"subPackages": [{
"root": "modules/settingModule",
"name": "settingModule",
"pages": [
"pages/setup/personal-data/personal-data",
"pages/setup/receive-address/add/add",
"pages/setup/receive-address/list/list"
]
}]
}
2. 将 个人资料 和 收货地址 目录移动到分包 settingModule 中
3. 替换 个人资料 和 收货地址 的访问路径
pages/setup/setup.wxml
<view class="container">
<view class="item-container">
<!-- 修改为 /modules/settingModule/ 起始的路径地址-->
<navigator class="item" url="/modules/settingModule/pages/setup/personal-data/personal-data">
<text>修改个人资料</text>
<text class="right">></text>
</navigator>
<navigator class="item" url="/modules/settingModule/pages/setup/receive-address/list/list">
<text>我的收货地址</text>
<text class="right">></text>
</navigator>
</view>
2. 分包预下载
app.json
{
"preloadRule": {
"pages/setup/setup": {
"network": "all",
"packages": ["settingModule"]
}
}
}
当点击进入设置页面时, 预下载了 settingModule 这个分包

3. 分页面构建
1. 个人资料

modules/settingModule/pages/setup/personal-data/personal-data.json
{
"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
}
modules/settingModule/pages/setup/personal-data/personal-data.wxml
<view class="container">
<view class="avatar">
<text class="avatar-text">头像</text>
<view class="right">
<image class="right-img" src="/assets/default.png" mode="" />
<text class="right-text">></text>
</view>
</view>
<view class="nickname">
<text class="nickname-text">头像</text>
<view class="right">
<text class="right-nickname">尚硅谷</text>
<text class="right-text">></text>
</view>
</view>
<view class="save-button">
<van-button round type="danger" size="large">保存</van-button>
</view>
</view>
modules/settingModule/pages/setup/personal-data/personal-data.scss
.container {
width: 100%;
height: 100%;
background-color: #efefef;
.avatar {
width: 100%;
height: 80rpx;
padding: 16rpx 20rpx;
background-color: white;
display: flex;
align-items: center;
justify-content: space-between;
.avatar-text {
font-size: 30rpx;
}
.right {
display: flex;
align-items: center;
.right-img {
width: 80rpx;
height: 80rpx;
margin-right: 30rpx;
}
.right-text {
margin-right: 50rpx;
font-size: 35rpx;
font-weight: 300;
color: #b8b1b1;
}
}
}
.nickname {
width: 100%;
height: 80rpx;
padding: 16rpx 20rpx;
background-color: white;
display: flex;
align-items: center;
margin-top: 15rpx;
justify-content: space-between;
.nickname-text {}
.right {
display: flex;
align-items: center;
.right-nickname {
width: 150rpx;
height: 80rpx;
line-height: 80rpx;
font-size: 28rpx;
margin-right: -40rpx;
}
.right-text {
margin-right: 50rpx;
font-size: 35rpx;
font-weight: 300;
color: #b8b1b1;
}
}
}
.save-button {
margin-top: 15rpx;
}
}
2. 收货地址

modules/settingModule/pages/setup/receive-address/receive-address.wxml
modules/settingModule/pages/setup/receive-address/receive-address.scss
3. 问题反馈
modules/settingModule/pages/setup/problem-feedback/problem-feedback.wxml
modules/settingModule/pages/setup/problem-feedback/problem-feedback.scss
4. 联系我们
modules/settingModule/pages/setup/contact-us/contact-us.wxml
modules/settingModule/pages/setup/contact-us/contact-us.scss
5. 授权信息
modules/settingModule/pages/setup/auth-info/auth-info.wxml
modules/settingModule/pages/setup/auth-info/auth-info.scss
5. 修改个人资料
1. 头像上传
通过 bindchooseavatar 事件回调获取到的头像信息的临时路径随时会失效, 因为小程序服务端会检测临时文件超过一定的容量时, 会将临时文件清理掉, 所以需要将头像信息的临时路径上传到自己的后台服务器, 如果想要将本地资源上传到服务器, 就需要使用到小程序提供的 API 方法: wx.uploadFile,
1. 原生 API的语法如下:
wx.uploadFile({
url: '开发者服务器地址',
filePath: '要上传文件资源的路径 (本地路径)',
name: '文件对应的 key',
header: 'HTTP 请求的 Header',
// 接口调用成功的回调函数
success: (res) =>{},
// 接口调用失败的回调函数
fail: (err) =>{}
})
2. 使用自己封装好的 uploadFile
api/user.js
import http from '@/utils/http'
export const reqUploadFile = (filePath, name) =>{
return http.upload('/fileUpload', filePath, name)
}
miniprogram/modules/settingModule/pages/setup/personal-data/personal-data.js
import { reqUploadFile } from '@/api/user'
Page({
data: {
avatar: ''
},
async getAvatar(event) {
const avatarUrl = event.detail.avatarUrl
// 发送请求, 将头像保存在服务器
const { data:avatar } = await reqUploadFile(avatarUrl)
this.setData({
avatar: avatar
})
}
})
2. 更新用户昵称 (弹出框)
1. 在app.json或index.json中引入组件
"usingComponents": {
"van-dialog": "@vant/weapp/dialog/index"
}
2. 页面中
modules/settingModule/setup/personal-data.wxml
<view class="nickname">
<text class="nickname-text">昵称</text>
<view class="right">
<!-- 绑定点击事件, 显示弹出框 -->
<text bindtap="onUpdateNickName" class="right-nickname">{{ userInfo.nickname || '尚硅谷' }}</text>
<text class="right-text">></text>
</view>
</view>
<!-- 修改用户昵称的弹出框, 默认隐藏 -->
<van-dialog custom-style="position: relative" use-slot title="修改昵称" show="{{ isShowPopup }}" showConfirmButton="{{false}}" showCancelButton="{{false}}" transition="fade">
<!-- 需要使用 form 组件 来收集数据, 并绑定提交事件的回调函数-->
<form bindsubmit="getNickname">
<!-- 需要给 input 输入框 添加 type="nickname" 来让用户授权获取微信昵称 -->
<!-- 需要添加 name 属性, form 组件才可以收集到 input 输入框的内容 -->
<input type="nickname" name="nickname" class="input-name" value="{{userInfo.nickname}}" />
<view class="dialog-content">
<!-- 给取消按钮添加 form-type="reset", 来重置表单中的所有数据内容 -->
<button class="cancel" bindtap="cancelForm" form-type="reset">取消</button>
<!-- 给确定按钮添加 form-type="submit", 将按钮变为提交按钮,在点击确定按钮时,会触发 from 组件的提交事件 -->
<button class="confirm" type="primary" form-type="submit">确定</button>
</view>
</form>
</van-dialog>
modules/settingModule/setup/personal-data.scss
van-dialog {
width: 100%;
.input-name {
margin: 20rpx 40rpx;
border-radius: 20rpx;
height: 80rpx;
border: 1rpx solid rgb(163, 160, 160);
}
.dialog-content {
display: flex;
}
}
modules/settingModule/setup/personal-data.js
import {
reqUpdateUserInfo
} from '@/api/user'
Page({
data: {
isShowPopup: false
},
// 显示修改昵称弹框
onUpdateNickName() {
this.setData({
isShowPopup: true,
'userInfo.nickname': this.data.userInfo.nickname
})
},
// 弹框取消按钮
cancelForm(){
this.setData({
isShowPopup: false
})
},
// 获取用户昵称
getNickname(event) {
const { nickname} = event.detail.value
this.setData({
'userInfo.nickname': nickname
})
},
})
3. 保存更新用户信息
1. 保存按钮绑定点击事件
modules/settingModule/setup/personal-data/personal-data.wxml
<van-button round type="danger" size="large" bindtap="updateUserInfo">保存</van-button>
2. 定义请求 API
api/user.js
import http from '@/utils/http'
/**
* @description 更新用户信息
* @param {Object} userInfo
* @returns Promise
*/
export const reqUpdateUserInfo = (userInfo) =>{
return http.post('/weixin/updateUser',userinfo)
}
3. 页面回调函数
modules/settingModule/setup/personal-data/personal-data.js
import {
reqUpdateUserInfo
} from '@/api/user'
Page({
data: {
},
// 更新用户信息
async updateUserInfo() {
const res = await reqUpdateUserInfo(this.data.userinfo)
if (res.code === 200){
// 用户信息更新成功后, 需要将最新的用户信息存储到本地, 并同步到store
setStorage('userInfo', this.data.userInfo)
this.setUserInfo(this.data.userInfo)
// 提示用户
toast({
title: '用户信息更新成功'
})
}
}
})
6. 我的收货地址
1. 列表
1. 页面构建
modules/settingModule/pages/setup/receive-address/list/list.json
{
"usingComponents": {
"van-button": "@vant/weapp/button/index",
"van-icon": "@vant/weapp/icon/index"
}
}
miniprogram/modules/settingModule/setup/receive-address/list/list.wxml
<view class="container">
<view class="address-content">
<view class="left">
<view class="content-top">
<text>测试用户</text>
<text>17600059660</text>
<text class="logo">默认</text>
</view>
<view class="content-bottom">
甘肃省甘南藏族自治州碌曲县松日鼎盛大厦1层
</view>
</view>
<navigator url="" class="right">
<text class="iconfont icon-bianji"></text>
</navigator>
<view class="editBtn" data-id="{{ item.id }}">
<van-icon name="edit" size="22px" color="#999" />
</view>
</view>
<navigator url="../add/add" class="address-bottom">
<van-button round type="danger" size="large">新增地址</van-button>
</navigator>
</view>
miniprogram/modules/settingModule/setup/receive-address/list/list.scss
.container {
position: relative;
height: 1200rpx;
background-color: #efefef;
.address-content {
height: 130rpx;
background-color: #fff;
padding: 30rpx;
border-bottom: 1rpx solid rgb(216, 210, 210);
margin-bottom: 10rpx;
display: flex;
align-items: center;
.left {
.content-top {
display: flex;
font-size: 26rpx;
text {
margin-right: 20rpx;
}
.logo {
background-color: #f6c6c6f3;
color: red;
}
}
.content-bottom {
margin-top: 15rpx;
font-size: 28rpx;
}
}
// 将按钮固定在右侧
.right {
position: fixed;
right: 45rpx;
.iconfont {
font-size: 34rpx;
}
}
}
// 将按钮固定在底部
.address-bottom {
width: 90%;
position: fixed;
bottom: 30rpx;
left: 40rpx;
}
.editBtn{
position: fixed;
right: 80rpx;
}
}
2. 数据交互
- 在
onShow()钩子函数中调用请求方法 - 在获取到数据以后, 使用后端返回的数据对页面进行渲染
miniprogram/modules/settingModule/setup/receive-address/list/list.js
import {reqAddressList} from '@/api/address'
Page({
data: {
addressList: []
},
getAddressList(){
const {data:addressList} = reqAddressList()
this.setData({
addressList
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
this.getAddressList()
},
})
miniprogram/modules/settingModule/setup/receive-address/list/list.wxml
<view class="container" wx:if="{{ addressList.length }}">
<view class="address-content" wx:for="{{ addressList }}" wx:key="id">
<view class="left">
<view class="content-top">
<text>{{ item.name }}</text>
<text>{{ item.phone }}</text>
<text wx:if="{{ item.isDefault === 1 }}" class="logo">默认</text>
</view>
<view class="content-bottom">
{{ item.fullAddress }}
</view>
</view>
<navigator url="" class="right">
<text class="iconfont icon-bianji"></text>
</navigator>
</view>
<navigator url="../add/add" class="address-bottom">
<van-button round type="danger" size="large">新增地址</van-button>
</navigator>
</view>
2. 新增
1. 页面构建
miniprogram/modules/settingModule/setup/receive-address/add/add.json
{
"usingComponents": {
"van-switch": "@vant/weapp/switch/index"
}
}
miniprogram/modules/settingModule/setup/receive-address/add/add.wxml
<view class="container">
<view class="item flex">
<text>收货人</text>
<input type="text" placeholder="请输入收货人姓名" />
</view>
<view class="item flex">
<text>手机号</text>
<input type="text" placeholder="请输入收货人手机号" />
</view>
<view class="item2 flex">
<text>所在地区</text>
<!-- 小程序 picker组件 mode:region 省市区选择器 -->
<!-- value 必须是一个数组, 用来存放选中的省市区 -->
<picker mode="region" value="{{ [] }}">
<view class="placeholder">请选择收货人所在城市</view>
</picker>
</view>
<view class="item2 flex">
<text>详细地址</text>
<input type="text" placeholder="门牌号(例: 5号楼1单元203室)" />
<view class="localtion">
<van-icon name="location-o" />
<text>定位</text>
</view>
</view>
<view class="default-address item3 flex">
<text>设置默认地址</text>
<van-switch size="50rpx" checked="{{ isDefault }}" bind:change="changeDefaultAddress" />
</view>
<button class="button">保存</button>
</view>
miniprogram/modules/settingModule/setup/receive-address/add/add.wxml
.flex {
display: flex;
}
.container {
padding: 20rpx;
.item {
width: 100%;
height: 80rpx;
align-items: center;
font-size: 30rpx;
border-bottom: 1rpx solid rgb(231, 221, 221);
text {
margin-right: 100rpx;
}
input {
width: 60%;
font-size: 28rpx;
}
}
.item2 {
width: 100%;
height: 80rpx;
align-items: center;
font-size: 30rpx;
border-bottom: 1rpx solid rgb(231, 221, 221);
text {
width: 20%;
margin-right: 50rpx;
}
textarea {
margin-left: 20rpx;
}
.placeholder {
font-size: 28rpx;
color: rgb(138, 135, 135);
}
.localtion{
margin-left: 20rpx;
}
}
.item3 {
width: 100%;
height: 80rpx;
align-items: center;
font-size: 30rpx;
border-bottom: 1rpx solid rgb(231, 221, 221);
text {
margin-right: 360rpx;
}
}
.button {
margin-top: 20rpx;
border: 1rpx solid #111111;
border-radius: 50rpx;
color: white;
background-color: #f3514f;
}
}
2. 收集省市区数据
miniprogram/modules/settingModule/setup/receive-address/add/add.wxml
<view class="item2 flex">
<text>所在地区</text>
<!-- 小程序 picker组件 mode:region 省市区选择器,value 必须是一个数组, 用来存放选中的省市区 -->
<picker
mode="region"
value="{{ [provinceName,cityName,districtName] }}"
bindchange="onAddressChange"
>
<!-- 判断 address.provinceName, 展示不同的标签内容 -->
<view class="region" wx:if="{{provinceName }}">
{{provinceName + ' ' + cityName + ' ' + districtName}}
</view>
<view class="placeholder" wx:else>请选择收货人所在城市</view>
</picker>
</view>
miniprogram/modules/settingModule/setup/receive-address/add/add.js
Page({
data: {
name: '', // 收货人
phone: '', // 手机号码
provinceName: '', // 省
provinceCode: '', // 省编码
cityName: '', // 市
cityCode: '', // 市编码
districtName: '', // 区
districtCode: '', // 区编码
address: '', // 详细地址
fullAddress: '', // 完整地址
isDefault: false // 是否默认地址
},
/**
* 设置默认地址按钮的回调函数
*/
changeDefaultAddress({
detail
}) {
this.setData({
isDefault: detail
})
},
/**
* 获取所在地区发生改变的数据, 并赋值给 data.address
*/
onAddressChange(event) {
const [provinceCode, cityCode, districtCode] = event.detail.code
const [provinceName, cityName, districtName] = event.detail.value
this.setData({
provinceCode,
cityCode,
districtCode,
provinceName,
cityName,
districtName
})
}
})
3. 获取表单数据
1. 方式一: 传统方式
- 给所有的
input添加name和value - 给
button按钮添加form-type="submit" - 给
from表单绑定submit 事件和回调函数
2. 方式二: 使用双向数据绑定来实现表单数据的获取,不支持对象类型的数据双向绑定
miniprogram/modules/settingModule/setup/receive-address/add/add.wxml
<view class="container">
<form>
<view class="item flex">
<text>收货人</text>
<!-- model:value 双向数据绑定 -->
<input
model:value="{{ name }}"
type="text"
placeholder="请输入收货人姓名"
/>
</view>
<view class="item flex">
<text>手机号</text>
<!-- model:value 双向数据绑定 -->
<input
model:value="{{ phone }}"
type="text"
placeholder="请输入收货人手机号"
/>
</view>
<view class="item2 flex">
<text>详细地址</text>
<textarea
model:value="{{ address }}"
auto-height
placeholder-style="color:#969799;font-size: 28rpx;"
placeholder="门牌号(例: 5号楼1单元203室)"
/>
</view>
<view class="default-address item3 flex">
<text>设置默认地址</text>
<!-- model:value 双向数据绑定 -->
<van-switch
model:checked="{{ isDefault }}"
size="50rpx"
bind:change="changeDefaultAddress"
/>
</view>
<!-- 添加点击事件 -->
<button class="button" bind:tap="saveAddressForm">保存</button>
</form>
</view>
4. 获取地理定位坐标
1. 申请开通
暂时只对部分类目的小程序开放, 需要先通过类目审核, 然后在小程序管理后台, 开发 => 开发管理 => 接口设置 中自主开通该接口权限
- wx.chooseLocation() 打开地图, 用户自己选择位置
- wx.getLocation() 获取当前设备的实时位置
2. 在 app.json 中配置 requiredPrivateInfos 进行声明启用, 如果需要调用 wx.getLocation() 则需要继续配置 permission 字段, 同时使用 scope.userLocation 声明收集用户选择的位置信息的目的
{
"requiredPrivateInfos": ["chooseLocation","getLocation"],
"permission": {
"scope.userLocation": {
"desc": "获取你的位置信息"
}
}
}
3. 页面中添加 定位的字体图标, 并绑定点击事件
miniprogram/modules/settingModule/setup/receive-address/add/add.json
{
"usingComponents": {
"van-icon": "@vant/weapp/icon/index"
}
}
miniprogram/modules/settingModule/setup/receive-address/add/add.wxml
<view class="location" bindtap="onLocation">
<van-icon name="location-o" color="#777" />
<text>定位</text>
</view>
miniprogram/modules/settingModule/setup/receive-address/add/add.js
Page({
/**
* 获取用户地理位置信息
*/
async onLocation() {
// 获取当前用户的地理位置, (经度、纬度、高度)
const res = await wx.getLocation()
console.log(res);
// 获取用户自己选择的地理位置
const res2 = await wx.chooseLocation()
console.log(res2);
}
})
5. 拒绝授权后的解决方案
在调用 wx.getLocation() 获取地理位置时, 如果用户选择拒绝授权, 代码会直接抛出错误, 在拒绝授权后, 再次调用 wx.getLocation() 时, 不会再次弹窗询问用户是否允许授权而是直接报错
import {toast} from '@/utils/extendAPI'
Page({
/**
* 获取用户地理位置信息
*/
async onLocation() {
// 使用 trycatch 来捕获错误, 并提示
try {
const res = await wx.getLocation()
console.log(res);
} catch (error) {
toast({title:'您拒绝授权获取地理位置'})
}
}
})
重新授权的流程

1. 方式一: 使用 API 打开小程序客户端授权页面设置授权信息
import {
toast,
modal
} from '@/utils/extendAPI'
Page({
/**
* @description 获取用户地理位置信息
*/
async onLocaltion() {
// 获取用户在当前小程序的所有授权信息
const {
authSetting
} = await wx.getSetting()
// 获取用户是否授权了获取当前位置的授权, 授权过: true,拒绝授权: false,未授权过: undefined
if (authSetting["scope.userLocation"] === false) {
// 用户拒绝授权后, 再次申请授权时,需要弹窗提醒用户是否需要授权
const modalRes = await modal({
title: '授权提示',
content: '需要获取地理位置信息, 请确认授权'
})
// 如果用户点击了取消, 则说明用户拒绝授权, 需要给用户进行提示
if (!modalRes) return toast({
title: "您拒绝了授权"
})
// 如果用户点击了确定, 则说明用户想再次申请授权,需要打开微信客户端小程序的授权页面
const {authSetting} = await wx.openSetting()
// 如果用户未修改授权信息,则提示用户授权失败
if (!authSetting["scope.userLocation"]) return toast({title: '授权失败'})
// 如果用户修改了授权信息, 则获取用户的地理位置信息
try {
const locationRes = await wx.getLocation()
console.log(locationRes);
} catch (error) {
toast({
title: "您拒绝授权获取位置信息"
})
}
} else {
try {
const locationRes = await wx.getLocation()
console.log(locationRes);
} catch (error) {
toast({
title: "您拒绝授权获取位置信息"
})
}
}
}
})
2. 方式二: 使用 button 组件打开小程序客户端授权页面设置授权信息
<view class="box">
<!-- 设置 open-type="openSetting" -->
<button type="primary" open-type="openSetting">打开授权页面</button>
</view>
6. 手动选择位置及逆地址解析
使用 wx.chooseLocation()能够很方便的让用户来选择地理位置, 但是返回的数据并没有包含省市区、省市区编码数据。这时候可以使用 腾讯位置服务 -- 微信小程序SDK,将返回的经度、纬度进行逆地址解析,转成详细地址
1. 配置小程序使用 腾讯位置服务
-
申请开发者密钥(key):申请密钥
-
开通webserviceAPI服务:控制台 ->应用管理 -> 我的应用 ->添加key-> 勾选WebServiceAPI -> 保存
(小程序SDK需要用到webserviceAPI的部分服务,所以使用该功能的KEY需要具备相应的权限)
-
下载微信小程序JavaScriptSDK,微信小程序 JavaScriptSDK v1.2,并放入项目根目录的
/libs/tencentMap/ -
安全域名设置,在小程序管理后台 -> 开发 -> 开发管理 -> 开发设置 -> “服务器域名” 中设置request合法域名,添加https://apis.map.qq.com
-
配置账户额度, 控制条 -> 配额管理 -> 账户额度 -> 逆地址解析 -> 配额分配 -> 配置应用及额度、并发量
2. LBS 逆地址解析代码示例
import QQMapWX from '@/libs/tencentMap/qqmap-wx-jssdk'
Page({
onLoad(){
// 实例化 QQMapWX
this.qqmapwx = new QQMapWX({
key: '上面申请的key'
})
},
async onLocaltion() {
const {latitude,longitude,name} = await wx.chooseLocation()
// 使用 reversGeocoder API方法进行逆地址解析
this.qqmapwx.reversGeocoder({
location:{
latitude,
longitude
},
success: (res) =>{
// 获取省市区及省市区编码信息
const {adcode,province,city,district} = res.result.ad_info
// 获取街道、门牌(可能都是空字符串)
const {street, street_number} = res.result.address_component
// 获取标准地址
const {standard_address} = res.result.formatted_addresses
// 对获取的数据格式化,赋值给 data 中的字段
this.setData({
provinceName: province,
provinceCode: adcode.replace(adcode.substring(2,6),'0000'), // 编码都是根据adcode按照规则组织的, 如果是省, 前两位保留, 后面的都是0
cityName: city,
cityCode: adcode.replace(adcode.substring(4,6),'00', // 如果是市, 前四位保留, 后面的都是0
districtName: district,
districtCode: district && adcode, // 如果是区, 全部保留, 东莞市、中山市、儋州市、嘉峪关市 因其下无区县级,则是空字符串即可
address: street + street_number + name,
fullAddress: standard_address + name
})
}
})
},
})
7. async-validator 表单验证
async-validator 是一个基于 JavaScript 的表单验证库, 支持异步验证规则和自定义验证规则, 主流的 UI 组件库 Ant-design 和 Element 中的表单验证都是基于 async-validator,可以更好的构建表单验证逻辑, 使得错误提示信息更加友好和灵活
1. 下载
npm i async-validator
2. 使用
import Schema from 'async-validator'
Page({
data: {
name: '123'
},
/**
* @description 对数据进行验证
*/
onValidator() {
// 定义验证规则
const rules = {
// key 是验证规则的名字, 和验证的数据保持一致
name: [{
required: true, // 校验数据的必填
message: 'name 不能为空' // 未通过检验的错误提示信息
}, {
type: 'string', // 校验数据的类型
message: 'name 不是字符串'
}, {
min: 2, // 最小长度
max: 3, // 最大长度
message: 'name 最少两个字,最多三个字'
}
/*
{
pattern: '', // 正则校验规则
message: 'name 格式错误'
}, {
validator: () => { // 自定义验证规则
}
}
*/
]
}
// 实例化构造函数, 并传入验证规则
const validator = new Schema(rules)
// 调用示例方法, 进行校验, 只会校验和验证规则同名的字段
// 参数一: 需要验证的数据, 要求数据必须是一个对象
// 参数二: 回调函数
validator.validate(this.data, (errors, fields) => {
// 如果验证成功, errors 是 null, 如果验证失败, errors 是数组, 数组中的每一项是每个校验规则的错误信息
// fields 是需要验证的属性, 属性值是一个数组, 数组中也包含着错误信息
if (errors) {
console.log('校验失败');
console.log(errors);
console.log(fields);
} else {
console.log('校验成功');
}
})
}
})
8. 校验收货地址表单
miniprogram/modules/settingModule/setup/receive-address/add/add.wxml
<!-- 添加点击事件 -->
<button class="button" bind:tap="saveAddressForm">保存</button>
miniprogram/modules/settingModule/setup/receive-address/add/add.js
import Schema from 'async-validator'
import {
toast
} from '@/utils/extendAPI';
Page({
data: {
name: '', // 收货人
phone: '', // 手机号码
provinceName: '', // 省
provinceCode: '', // 省编码
cityName: '', // 市
cityCode: '', // 市编码
districtName: '', // 区
districtCode: '', // 区编码
address: '', // 详细地址
fullAddress: '', // 完整地址
isDefault: false // 是否默认地址
},
/**
* @description 收集表单数据, 校验成功后发送请求将收货人地址保存到服务器
*/
async saveAddressForm() {
// 组织成后端需要的参数 (完整地址, 是否设置为默认地址)
const {
provinceName,
cityName,
districtName,
address,
isDefault
} = this.data
const params = {
...this.data,
fullAddress: provinceName + cityName + districtName + address,
isDefault: isDefault ? 1 : 0
}
// 校验表单数据
const {
valid
} = await this.validatorFormData(params)
// 如果验证失败, 则直接return, 不执行下面的逻辑
if (!valid) return
// 如果验证成功, 发送请求, 保存收货地址到后端
const res = await reqAddAddress(params)
if (res.code === 200) {
wx.navigateBack()
toast({
title: '新增收货地址成功'
})
}
},
/**
* @description 对收货地址数据进行校验
* @param {Object} params
*/
validatorFormData(params) {
const nameRegExp = `[A-Za-z\\d\\\u4e00-\\u9fa5]+$`
const phoneRegExp = `1(?:3\\d|4[4-9]|5[0-35-9]|6[67]|7[0-8]|8\\d|9\\d)\\d{8}$`
const rules = {
name: [{
required: true,
message: '请输入收货人姓名'
}, {
pattern: nameRegExp,
message: '收货人姓名不合法'
}],
phone: [{
required: true,
message: '请输入收货人手机号'
}, {
pattern: phoneRegExp,
message: '收货人手机号不合法'
}],
provinceName: {
required: true,
message: '请选择收货人所在地区'
},
address: {
required: true,
message: '请输入详细地址'
}
}
const validator = new Schema(rules)
// 封装为 Promise 方式调用
return new Promise((resolve) => {
validator.validate(params, (errors) => {
if (errors) {
// 如果验证失败, 则需要给用户弹框提示
toast({
title: errors[0].message
})
// 如过返回值是 false, 则说明验证失败
resolve({
valid: false
})
} else {
// 如过返回值是 true, 则说明验证成功
resolve({
valid: true
})
}
})
})
},
})
9. 保存收货地址到后端
miniprogram/modules/settingModule/setup/receive-address/add/add.js
import Schema from 'async-validator'
import {
toast
} from '@/utils/extendAPI';
import {reqAddressData} from '@/api/address'
Page({
data: {
name: '', // 收货人
phone: '', // 手机号码
provinceName: '', // 省
provinceCode: '', // 省编码
cityName: '', // 市
cityCode: '', // 市编码
districtName: '', // 区
districtCode: '', // 区编码
address: '', // 详细地址
fullAddress: '', // 完整地址
isDefault: false // 是否默认地址
},
/**
* @description 收集表单数据, 校验成功后发送请求将收货人地址保存到服务器
*/
async saveAddressForm() {
// 组织成后端需要的参数 (完整地址, 是否设置为默认地址)
const {
provinceName,
cityName,
districtName,
address,
isDefault
} = this.data
const params = {
...this.data,
fullAddress: provinceName + cityName + districtName + address,
isDefault: isDefault ? 1 : 0
}
// 校验表单数据
const {
valid
} = await this.validatorFormData(params)
// 如果验证失败, 则直接return, 不执行下面的逻辑
if (!valid) return
// 如果验证成功, 发送请求, 保存收货地址到后端
const res = await reqAddressData(params)
if (res.code === 200){
// 返回收货地址列表页面
wx.navigateBack()
// 提示新增成功
toast({title: '新增收货地址成功! '})
}else{
}
},
/**
* @description 对收货地址数据进行校验
* @param {Object} params
*/
validatorFormData(params) {
const nameRegExp = `[A-Za-z\\d\\\u4e00-\\u9fa5]+$`
const phoneRegExp = `1(?:3\\d|4[4-9]|5[0-35-9]|6[67]|7[0-8]|8\\d|9\\d)\\d{8}$`
const rules = {
name: [{
required: true,
message: '请输入收货人姓名'
}, {
pattern: nameRegExp,
message: '收货人姓名不合法'
}],
phone: [{
required: true,
message: '请输入收货人手机号'
}, {
pattern: phoneRegExp,
message: '收货人手机号不合法'
}],
provinceName: {
required: true,
message: '请选择收货人所在地区'
},
address: {
required: true,
message: '请输入详细地址'
}
}
const validator = new Schema(rules)
// 封装为 Promise 方式调用
return new Promise((resolve) => {
validator.validate(params, (errors) => {
if (errors) {
// 如果验证失败, 则需要给用户弹框提示
toast({
title: errors[0].message
})
// 如过返回值是 false, 则说明验证失败
resolve({
valid: false
})
} else {
// 如过返回值是 true, 则说明验证成功
resolve({
valid: true
})
}
})
})
}
})
miniprogram/api/address.js
import http from '@/utils/http'
export const reqAddressData = (data) => {
return http.post('/userAddress/save',data)
}
3. 编辑
新增和编辑收货地址页面用的是同一个页面, 在收货地址列表页面中点击更新按钮时, 需要跳转到新增/更新页面, 同时需要将更新这一项的 id 传递给新增/更新页面
在 onLoad() 中获取 id, 并且使用 id 来区分用户是进行新增还是编辑操作
如果存在 id, 再获取需要更新的收货地址的数据, 并进行页面的回显收货地址数据, 并且需要更新导航栏标题
miniprogram/modules/settingModule/setup/receive-address/list/list.wxml
<view class="container" wx:if="{{ addressList.length }}">
<view class="address-content" wx:for="{{ addressList }}" wx:key="id">
<!-- 绑定点击事件 -->
<view class="editBtn" data-id="{{ item.id }}" bind:tap="toEdit">
<van-icon name="edit" size="22px" color="#999" />
</view>
</view>
</view>
miniprogram/modules/settingModule/setup/receive-address/list/list.js
Page({
toEdit(event){
// 获取要更新的收货地址id
const {id} = event.currentTarget.dataset
wx.navigateTo({
url: `/modules/settingModule/pages/setup/receive-address/add/add?id=${id}`,
})
},
})
miniprogram/modules/settingModule/setup/receive-address/add/add.js
Page({
onLoad(options) {
// 实例化 QQMapWX
this.qqmapwx = new QQMapWX({
key: '上面申请的key'
})
// 判断是否携带参数id
if (options.id) this.showAddressInfo
},
async showAddressInfo(id){
// 将id 挂载在当前页面的实例(this)上, 方便在多个方法中使用
this.addressId = id
// 动态设置当前页面的导航栏标题
wx.setNavigationBarTitle({
title: '修改收货地址',
})
// 调用接口API 来获取收货地址详情, 并回显
const {data} = await reqAddressInfo(id)
this.setData(data)
},
/**
* @description 收集表单数据, 校验成功后发送请求将收货人地址保存到服务器
*/
async saveAddressForm() {
// ......
// 根据是否有 addressId 来分辨用户是想编辑还是新增
const res = this.addressId ? await reqUpdateAddress(params) : await reqAddAddress(params)
if (res.code === 200) {
wx.navigateBack()
toast({
title: this.addressId ? '修改收货地址成功!' :'新增收货地址成功!'
})
}
}
})
4. 删除
1. 功能实现
SwipeCell 滑动单元格
miniprogram/modules/settingModule/setup/receive-address/list/list.json
{
"usingComponents": {
"van-swipe-cell": "@vant/weapp/swipe-cell/index"
}
}
miniprogram/modules/settingModule/setup/receive-address/list/list.wxml
<view class="container" wx:if="{{ addressList.length }}">
<view class="address-content" wx:for="{{ addressList }}" wx:key="id">
<van-swipe-cell right-width="{{ 65 }}">
<van-cell-group>
<view class="list-item">
<van-cell>
<view class="left">
<view class="content-top">
<text>{{ item.name }}</text>
<text>{{ item.phone }}</text>
<text wx:if="{{ item.isDefault === 1 }}" class="logo">默认</text>
</view>
<view class="content-bottom">
{{ item.fullAddress }}
</view>
</view>
<view class="editBtn" data-id="{{ item.id }}" bind:tap="toEdit">
<van-icon name="edit" size="22px" color="#999" />
</view>
</van-cell>
</view>
</van-cell-group>
<view slot="right" class="van-swipe-cell__right" bind:tap="delAddress" data-id="{{ item.id }}">
<text>删除</text>
</view>
</van-swipe-cell>
</view>
<navigator url="../add/add" class="address-bottom">
<van-button round type="danger" size="large">新增地址</van-button>
</navigator>
</view>
miniprogram/modules/settingModule/setup/receive-address/list/list.scss
.container {
position: relative;
height: 1200rpx;
background-color: #efefef;
.address-content {
height: 130rpx;
background-color: #fff;
padding: 30rpx;
border-bottom: 1rpx solid rgb(216, 210, 210);
margin-bottom: 10rpx;
display: flex;
align-items: center;
van-swipe-cell {
width: 100%;
van-cell-group {
.list-item {
width: 100%;
display: flex;
.left {
.content-top {
display: flex;
font-size: 26rpx;
text {
margin-right: 20rpx;
}
.logo {
background-color: #f6c6c6f3;
color: red;
}
}
.content-bottom {
margin-top: 15rpx;
font-size: 28rpx;
}
}
.editBtn {
position: fixed;
right: 60rpx;
margin-left: 40rpx;
}
}
}
.van-swipe-cell__right{
color: red;
}
}
}
// 将按钮固定在底部
.address-bottom {
width: 90%;
position: fixed;
bottom: 30rpx;
left: 40rpx;
}
}
miniprogram/modules/settingModule/setup/receive-address/list/list.js
Page({
// 删除收货地址
async delAddress(event) {
const {
id
} = event.currentTarget.dataset
// 询问用户是否删除
const res = await modal({
content: "您去人删除该收货地址吗?"
})
if (res) {
// 调用接口,删除该收货地址
const res = await reqDelAddress(id)
if (res.code === 200) {
toast({
title: "删除成功"
})
// 重新获取收货地址列表数据
this.getAddressList()
}
}
}
})
2. 自动收起滑块优化
由于其他页面也需要使用到这个逻辑, 所以将公共逻辑抽取成behavior
miniprogram/behaviors/swipeCell.js
export const swipeCellBehavior = Behavior({
data: {
swipeCellQueue: []
},
methods: {
// 当用户打开滑块时,将id
swipeCellOpen(event) {
// 获取当前单元格实例
const instance = this.selectComponent(`#swipe-cell-${event.currentTarget.dataset.id}`)
// 将实例追加到数组中
this.data.swipeCellQueue.push(instance)
},
// 关闭滑块公共逻辑
onSwipeCellCommonClick() {
this.data.swipeCellQueue.forEach(instance => {
instance.close()
})
// 将滑动单元格数组置空
this.data.swipeCellQueue = []
},
// 利用事件冒泡绑定点击事件
onSwipeCellPage() {
this.onSwipeCellCommonClick()
},
// 点击滑动单元格的按钮时触发的事件
onSwipeCellClick() {
this.onSwipeCellCommonClick()
}
}
})
miniprogram/modules/settingModule/setup/receive-address/list/list.wxml
<view class="container" wx:if="{{ addressList.length }}" bind:tap="onSwipeCellPage">
<view class="address-content" wx:for="{{ addressList }}" wx:key="id">
<van-swipe-cell id="swipe-cell-{{ item.id }}" data-id="{{ item.id }}" bind:click="onSwipeCellClick" bind:open="swpeCellOpen" right-width="{{ 65 }}">
</van-swipe-cell>
</view>
</view>
miniprogram/modules/settingModule/setup/receive-address/list/list.js
import {
swipeCellBehavior
} from '@/behaviors/swipeCell'
Page({
behaviros: [swipeCellBehavior],
})

浙公网安备 33010602011771号