登录模块


小程序快捷登录
状态管理:(类型修改),调用useMemberStore的setProfile函数来保存会员信息
页面跳转:因为 我的 是开发页,使用uni.switchTab来实现tabBar跳转



模拟快捷登录
保存登录信息

状态管理:(类型修改),调用useMemberStore的setProfile函数来保存会员信息
页面跳转:因为 我的 是开发页,使用uni.switchTab来实现tabBar跳转
会员中心
会员信息展示


猜你喜欢分页加载

设置页分包和预下载



退出登录

html
<script setup lang="ts">
import { useMemberStore } from '@/stores'
const memberStore = useMemberStore()
//退出登录
const onLogout = () => {
//模态弹窗
uni.showModal({
content: '是否退出登录?',
success: (res) => {
if (res.confirm) {
//清理用户信息
memberStore.clearProfile()
//返回上一页
uni.navigateBack()
}
}
})
}
</script>
<templete>
<view class="action" v-if="memberStore.profile">
<view @tap="onLogout" class="button">退出登录</view>
</view>
</templete>
个人信息
准备工作

获取和渲染
修改用户头像




修改用户昵称





同步头像昵称
修改性别




修改生日
注意使用具体模式是UniHelper.DatePickerOnChange ,且mode为date就能获取到选择的日期,日期从ev.detail.value里;最后把参数传递给后端,让后端更新

html
<script>//点击提交表单
const onSubmit = async () => {
const { nickname, gender, birthday } = profile.value
const res = await putMemberProfileAPI({
nickname,
gender,
birthday
})
//更新store昵称
memberStore.profile!.nickname = res.result.nickname
uni.showToast({
icon: 'success',
title: '保存成功'
})
setTimeout(() => {
uni.navigateBack()
}, 400)
}
//修改性别
const onGenderchange: UniHelper.RadioGroupOnChange = (ev) => {
profile.value.gender = ev.detail.value as Gender
}
//修改生日
const onBirthdayChange: UniHelper.DatePickerOnChange = (ev) => {
profile.value.birthday = ev.detail.value
}</script>
<templete>
<picker
@change="onBirthdayChange"
class="picker"
mode="date"
start="1900-01-01"
:end="new Date()"
:value="profile.birthday"
>
<view v-if="profile.birthday">{{ profile?.birthday }}</view>
<view class="placeholder" v-else>请选择日期</view>
</picker>
</templete>
修改城市






技术点总结
地址模块
准备工作
html
//获取页面参数
const query = defineProps<{
id?: string
}>()
//动态设置标题
uni.setNavigationBarTitle({ title: query.id ? '修改地址' : '新建地址' })


html
<script setup lang="ts">
import { postMemberAddressAPI } from '@/services/address'
import { ref } from 'vue'
// 表单数据
const form = ref({
receiver: '', // 收货人
contact: '', // 联系方式
fullLocation: '', // 省市区(前端展示)
provinceCode: '', // 省份编码(后端参数)
cityCode: '', // 城市编码(后端参数)
countyCode: '', // 区/县编码(后端参数)
address: '', // 详细地址
isDefault: 0, // 默认地址,1为是,0为否
})
// 收集所在地区
const onRegionChange: UniHelper.RegionPickerOnChange = (ev) => {
// 省市区(前端展示)
form.value.fullLocation = ev.detail.value.join(' ')
// 省市区(后端参数)
const [provinceCode, cityCode, countyCode] = ev.detail.code!
// 合并数据
Object.assign(form.value, { provinceCode, cityCode, countyCode })
}
// 收集是否默认收货地址
const onSwitchChange: UniHelper.SwitchOnChange = (ev) => {
form.value.isDefault = ev.detail.value ? 1 : 0
}
// 提交表单
const onSubmit = async () => {
// 新建地址请求
await postMemberAddressAPI(form.value)
// 成功提示
uni.showToast({ icon: 'success', title: '添加成功' })
// 返回上一页
setTimeout(() => {
uni.navigateBack()
}, 400)
}
</script>
<template>
<view class="content">
<form>
<!-- 表单内容 -->
<view class="form-item">
<text class="label">收货人</text>
<input class="input" placeholder="请填写收货人姓名" v-model="form.receiver" />
</view>
<view class="form-item">
<text class="label">手机号码</text>
<input class="input" placeholder="请填写收货人手机号码" v-model="form.contact" />
</view>
<view class="form-item">
<text class="label">所在地区</text>
<picker
class="picker"
mode="region"
:value="form.fullLocation.split(' ')"
@change="onRegionChange"
>
<view v-if="form.fullLocation">{{ form.fullLocation }}</view>
<view v-else class="placeholder">请选择省/市/区(县)</view>
</picker>
</view>
<view class="form-item">
<text class="label">详细地址</text>
<input class="input" placeholder="街道、楼牌号等信息" v-model="form.address" />
</view>
<view class="form-item">
<label class="label">设为默认地址</label>
<switch
class="switch"
color="#27ba9b"
:checked="form.isDefault === 1"
@change="onSwitchChange"
/>
</view>
</form>
</view>
<!-- 提交按钮 -->
<button @tap="onSubmit" class="button">保存并使用</button>
</template>
TypeScript
src/services/address.ts:import type { AddressParams } from '@/types/address'
import { http } from '@/utils/http'
/**
* 添加收货地址
* @param data 请求参数
*/
export const postMemberAddressAPI = (data: AddressParams) => {
return http({
method: 'POST',
url: '/member/address',
data,
})
}
TypeScript
/** 添加收货地址: 请求参数 */
export type AddressParams = {
/** 收货人姓名 */
receiver: string
/** 联系方式 */
contact: string
/** 省份编码 */
provinceCode: string
/** 城市编码 */
cityCode: string
/** 区/县编码 */
countyCode: string
/** 详细地址 */
address: string
/** 默认地址,1为是,0为否 */
isDefault: number
}
新建地址




列表渲染
注意事项:
-
onLoad(只执行 1 次) 页面加载时执行 只执行一次 只要不销毁页面,返回再进来也不执行 👉 适合:只需要加载一次的数据
-
onShow(每次显示都执行) 页面显示 / 出现的时候执行 每次回来都会跑 从别的页面 返回 → 立刻执行 👉 适合:需要实时刷新的数据(地址列表、订单、个人中心)
修改地址
数据回显


提交表单
表单校验





删除地址






SKU模块
插件基本使用







渲染商品信息

打开弹窗设置按钮模式


计算被选中的值




加入购物车



购物车模块
列表渲染
删除单品



修改单品数量
GET = 拿数据(查购物车) POST = 新增(加入购物车) DELETE = 删除(删掉商品) PUT = 修改(改数量、改选中状态)

TypeScript
<script>
//点击删除按钮
const onDeleteCart = (skuId: string) => {
//弹窗二次确认
uni.showModal({
content: '是否删除',
success: async (res) => {
if (res.confirm) {
await deletsMemberCartAPI({ ids: [skuId] })
console.log('执行了删除')
//重新获取列表
getMemberCartData()
console.log('执行力重新获取')
}
},
})
}
//修改商品数量
const onChangeCount = (ev: InputNumberBoxEvent) => {
console.log(ev)
putMemberCartBySkuIdAPI(ev.index, { count: ev.value })
}
</script>
<templete>
<!-- 商品数量 -->
<view class="count">
<vk-data-input-number-box
v-model="item.count"
:min="1"
:max="item.stock"
:index="item.skuId"
@change="onChangeCount"
/>
</view>
<!-- 右侧删除按钮 -->
<template #right>
<view class="cart-swipe-right">
<button class="button delete-button" @tap="onDeleteCart(item.skuId)">删除 </button>
</view>
</template>
修改选中状态


reduce 是数组方法,专门用来:把一堆数据 → 汇总成 1 个结果
数组.reduce((累加器, 当前项) => { // 计算逻辑 return 新的累加器 }, 初始值)










