地址管理
账号管理-效果
账号管理-静态结构
src\pages\my\settings.vue
vue
<template>
<view class="viewport">
<!-- 🔔 已登录的用户才能修改收货地址 -->
<template v-if="profile">
<!-- 操作列表 -->
<view class="list">
<navigator url="./address/index" hover-class="none" class="item arrow"
>我的收货地址</navigator
>
</view>
<view class="list">
<navigator url="./account" hover-class="none" class="item arrow"
>账户与安全</navigator
>
</view>
</template>
<view class="list">
<button hover-class="none" class="item arrow" open-type="feedback">
问题反馈
</button>
<button hover-class="none" class="item arrow" open-type="contact">
联系我们
</button>
<navigator hover-class="none" url=" " class="item arrow"
>关于小兔鲜儿</navigator
>
</view>
</view>
</template>
<script>
// 记得把 vuex中的用户信息引过来
export default {};
</script>
<style lang="scss">
page {
background-color: #f4f4f4;
}
button {
text-align: left;
border-radius: 0;
background-color: #fff;
&::after {
width: auto;
height: auto;
left: auto;
border: none;
}
}
.viewport {
padding: 20rpx;
}
.arrow {
&::after {
position: absolute;
top: 50%;
content: "\e6c2";
color: #ccc;
font-family: "erabbit" !important;
font-size: 32rpx;
transform: translateY(-50%);
}
}
.list {
padding: 0 20rpx;
background-color: #fff;
margin-bottom: 20rpx;
border-radius: 10rpx;
.item {
line-height: 90rpx;
padding-left: 10rpx;
font-size: 30rpx;
color: #333;
border-top: 1rpx solid #ddd;
position: relative;
&:first-child {
border: none;
}
}
}
.item {
&::after {
right: 5rpx;
}
}
</style>
地址管理-效果
地址管理-静态结构
src\pages\my\address\index.vue
vue
<template>
<view class="viewport">
<!-- 地址列表 -->
<scroll-view scroll-y>
<view class="address">
<!-- 按组使用 -->
<uni-swipe-action>
<uni-swipe-action-item class="swipe-cell">
<view class="item" v-for="item in 3" :key="item">
<view class="user">
收件人
<text>联系电话</text>
<text class="badge"> 默认 </text>
</view>
<view class="locate"> 河北省唐山市 路北区小巷子 </view>
<!-- 🐛 添加阻止冒泡 -->
<navigator
:url="`./form?id=${item.id}`"
class="edit"
hover-class="none"
>
修改
</navigator>
</view>
<template v-slot:right>
<view class="swipe-cell-action">
<button class="delete-button">删除</button>
</view>
</template>
</uni-swipe-action-item>
</uni-swipe-action>
</view>
</scroll-view>
<!-- 添加按钮 -->
<view class="add-btn">
<navigator hover-class="none" url="./form">新建地址</navigator>
</view>
</view>
</template>
<script>
export default {};
</script>
<style lang="scss">
page {
height: 100%;
overflow: hidden;
}
.viewport {
display: flex;
flex-direction: column;
height: 100%;
background-color: #f4f4f4;
scroll-view {
padding-top: 20rpx;
}
}
.address {
padding: 0 20rpx;
margin: 0 20rpx;
border-radius: 10rpx;
background-color: #fff;
.item {
line-height: 1;
padding: 40rpx 10rpx 38rpx;
border-bottom: 1rpx solid #ddd;
position: relative;
.user {
font-size: 28rpx;
margin-bottom: 20rpx;
color: #333;
text {
color: #666;
}
.badge {
display: inline-block;
padding: 4rpx 10rpx 2rpx 14rpx;
margin: 2rpx 0 0 10rpx;
font-size: 26rpx;
color: #27ba9b;
border-radius: 6rpx;
border: 1rpx solid #27ba9b;
}
}
.locate {
line-height: 1.6;
font-size: 26rpx;
color: #333;
}
.edit {
position: absolute;
top: 36rpx;
right: 30rpx;
padding: 2rpx 0 2rpx 20rpx;
border-left: 1rpx solid #666;
font-size: 26rpx;
color: #666;
line-height: 1;
}
}
.swipe-cell {
&:last-child {
.item {
border: none;
}
}
}
}
.swipe-cell-action {
height: 100%;
.delete-button {
display: flex;
justify-content: center;
align-items: center;
width: 50px;
height: 100%;
font-size: 28rpx;
color: #fff;
border-radius: 0;
padding: 0;
background-color: #cf4444 !important;
}
}
.add-btn {
height: 80rpx;
text-align: center;
line-height: 80rpx;
margin: 30rpx 20rpx;
color: #fff;
border-radius: 80rpx;
font-size: 30rpx;
background-color: #27ba9b;
}
.blank {
margin-top: 300rpx;
text-align: center;
font-size: 32rpx;
color: #888;
}
</style>
地址管理-请求数据、渲染界面
步骤:
1、封装API
2、封装请求函数,调用API
3、加载后,触发请求函数
4、声明变量,保存数据
代码:
src\api\category.js
js
export const getAddressAPI = () => {
return request({
url: "/member/address",
});
};
src/pages/my/address/index.vue
vue
<script>
import { getAddressAPI } from "@/api/address";
export default {
data() {
return {
list: [],
};
},
methods: {
async loadData() {
const { result } = await getAddressAPI();
this.list = result;
},
},
onLoad() {
this.loadData();
},
};
</script>
html
<view class="item" v-for="item in list" :key="item.id">
<view class="user">
收件人
<text>联系电话</text>
<text class="badge"> 默认 </text>
{{ item.receiver }}
<text>{{ item.contact }}</text>
<text class="badge" v-if="item.isDefault"> 默认 </text>
</view>
<view class="locate"> 河北省唐山市 路北区小巷子 </view>
<view class="locate">
{{ item.fullLocation }} {{ item.address }}
</view>
</view>
新增地址-效果
新增地址-静态结构
src\pages\my\address\form.vue
vue
<template>
<view class="viewport">
<!-- 地址信息 -->
<view class="form">
<view class="form-item">
<text class="label">姓名</text>
<input
v-model="form.receiver"
placeholder-style="color: #888"
placeholder="请填写收货人姓名"
/>
</view>
<view class="form-item">
<text class="label">手机号码</text>
<input
v-model="form.contact"
placeholder-style="color: #888"
placeholder="请填写收货人手机号码"
/>
</view>
<view class="form-item">
<text class="label">省/市/县 (区)</text>
<picker @change="regionChange" mode="region">
<view v-if="form.fullLocation" class="region">
{{ form.fullLocation }}
</view>
<view v-else class="placeholder"> 请填写收货人所在城市 </view>
</picker>
</view>
<view class="form-item">
<text class="label">详细地址</text>
<input
v-model="form.address"
placeholder-style="color: #888"
placeholder="街道、楼牌号信息"
/>
</view>
<view class="form-item">
<text class="label">设置默认地址</text>
<switch
@change="onChangeDefault"
:checked="form.isDefault === 1"
color="#27ba9b"
/>
</view>
</view>
<!-- 提交按钮 -->
<view class="button" @tap="submitForm"> 保 存 </view>
</view>
</template>
<script>
export default {
data() {
return {
form: {
/** * 详细地址 */
address: "",
/** * 联系方式 */
contact: "",
/** * 是否为默认,1为是,0为否 */
isDefault: 0,
/** * 收货人姓名 */
receiver: "",
/** 省市县 */
fullLocation: "",
/** * 所在区/县编码 */
countyCode: "",
/** * 所在城市编码 */
cityCode: "",
/** * 所在省份编码 */
provinceCode: "",
},
};
},
};
</script>
<style lang="scss">
page {
background-color: #f4f4f4;
}
.form {
margin: 20rpx 20rpx 0;
padding: 0 20rpx;
border-radius: 10rpx;
background-color: #fff;
.form-item {
display: flex;
min-height: 96rpx;
line-height: 46rpx;
padding: 25rpx 10rpx;
background-color: #fff;
font-size: 28rpx;
border-bottom: 1rpx solid #ddd;
position: relative;
&:last-child {
border: none;
}
.label {
width: 200rpx;
color: #333;
}
input {
flex: 1;
display: block;
height: 46rpx;
}
switch {
position: absolute;
right: -10rpx;
transform: scale(0.7) translateY(-8px);
}
picker {
flex: 1;
}
.region {
color: #333;
}
.placeholder {
color: #888;
}
}
}
.button {
height: 80rpx;
text-align: center;
line-height: 80rpx;
margin: 30rpx 20rpx;
color: #fff;
border-radius: 80rpx;
font-size: 30rpx;
background-color: #27ba9b;
}
</style>
新增地址-双向绑定
diff
<template>
<view class="viewport">
<!-- 地址信息 -->
<view class="form">
<view class="form-item">
<text class="label">姓名</text>
<input
+ v-model="form.receiver"
placeholder-style="color: #888"
placeholder="请填写收货人姓名"
/>
</view>
<view class="form-item">
<text class="label">手机号码</text>
<input
+ v-model="form.contact"
placeholder-style="color: #888"
placeholder="请填写收货人手机号码"
/>
</view>
<view class="form-item">
<text class="label">省/市/县 (区)</text>
<picker
+ @change="onChangeRegion"
mode="region"
>
<view v-if="form.fullLocation" class="region">
{{ form.fullLocation }}
</view>
<view v-else class="placeholder"> 请填写收货人所在城市 </view>
</picker>
</view>
<view class="form-item">
<text class="label">详细地址</text>
<input
+ v-model="form.address"
placeholder-style="color: #888"
placeholder="街道、楼牌号信息"
/>
</view>
<view class="form-item">
<text class="label">设置默认地址</text>
<switch
+ @change="onChangeDefault"
:checked="form.isDefault === 1"
color="#27ba9b"
/>
</view>
</view>
<!-- 提交按钮 -->
<view class="button"> 保 存 </view>
</view>
</template>
<script>
export default {
+ methods: {
+ onChangeDefault(e) {
+ this.form.isDefault = e.detail.value ? 1 : 0;
+ },
+ onChangeRegion(e) {
+ const { code, value, postcode } = e.detail;
+ this.form.fullLocation = value.join("");
+ this.form.provinceCode = code[0];
+ this.form.cityCode = code[1];
+ this.form.countyCode = code[2];
+ },
+ },
};
</script>
新增地址-实现新增
src/api/address.js
js
/**
* 添加收货地址
*/
export const addAddressAPI = (data) => {
return request({
url: "/member/address",
method: "post",
data,
});
};
src/pages/my/address/form.vue
js
async onSubmit() {
await addAddressAPI(this.form);
uni.showToast({
title: "新增成功",
icon: "success",
});
setTimeout(() => {
uni.navigateBack();
}, 1000);
},
编辑地址
编制地址页面可以和新建地址页面共用一个页面
src/api/address.js
js
/**
* 更新收货地址
*/
export const updateAddressAPI = (id, data) => {
return request({
url: `/member/address/${id}`,
method: "put",
data,
});
};
src/pages/my/address/form.vue
js
// 2. 获取id,判断是否为编辑
async onLoad({ id }) {
if (id) {
// 3. 查询表单数据
const { result } = await getAddressDetailAPI(id);
// 4. 回填表单信息
this.form = { ...result };
// 5. 修改标题
uni.setNavigationBarTitle({ title: "编辑地址" });
}
},
diff
async onSubmit() {
- await addAddressAPI(this.form);
// 3. 更新表单
+ if (this.form.id) {
+ const obj = { ...this.form };
+ delete obj.id;
+ await updateAddressAPI(this.form.id, obj);
+ } else {
+ await addAddressAPI(this.form);
+ }
uni.showToast({
- title: "新增成功",
// 4. 替换文字
+ title: this.form.id ? "编辑成功" : "新增成功",
icon: "success",
});
setTimeout(() => {
uni.navigateBack();
}, 1000);
},
删除地址
- 在显示地址时,我们使用了
uni-ui
提供的uni-swipe-action
滑动组件,实现滑动删除地址 - 当用户点击
删除
时,先弹出一个对话模态框,当用户确定删除时,再执行删除功能。
src/api/address.js
js
/**
* 删除收货地址
*/
export const delAddressAPI = (id) => {
return request({
url: `/member/address/${id}`,
method: "delete",
});
};
src/pages/my/address/form.vue
diff
<template v-slot:right>
- <view class="swipe-cell-action">
+ <view class="swipe-cell-action" @click="onDelById(item.id)">
<button class="delete-button">删除</button>
</view>
</template>
js
async onDelById(id) {
// 💥💥 注意增加二次确认
const [err, { confirm }] = await uni.showModal({
title: "提示",
content: "确认删除吗?",
});
if (!err && confirm) {
await delAddressAPI(id);
uni.showToast({
title: "删除成功",
icon: "success",
});
this.list = this.list.filter((item) => {
return item.id !== id;
});
}
},