在uniapp中实现添加收货地址功能,需创建表单页面包含收货人、手机号、省市区选择(使用picker组件联动)及详细地址输入,通过uni.setStorageSync存储地址数据至本地,或调用接口提交至后端,表单需校验手机号格式、地址完整性等必填项,提交成功后通过uni.showToast提示,并返回上一页刷新列表,核心代码包括表单双向绑定、省市区数据联动及本地存储逻辑,确保用户便捷管理收货信息。
Uniapp实现添加收货地址功能:从零开始的详细教程
在电商、外卖、社区团购等类型的应用中,收货地址管理都是核心功能之一,本文将详细介绍如何使用Uniapp框架从零开始实现"添加收货地址"功能,涵盖页面结构设计、表单验证、省市区联动、本地存储等关键环节,帮助开发者快速掌握这一常见功能的开发方法。
环境准备与项目创建
在开始编码前,确保已安装以下工具:
- HBuilderX:Uniapp官方推荐IDE,支持代码编写、调试和打包。
- Uniapp项目模板:可通过HBuilderX创建"默认模板"项目,选择Vue2或Vue3(本文以Vue2为例)。
创建项目后,在pages目录下新建address文件夹,并添加add-address.vue文件,作为添加收货地址的页面。
页面结构设计:表单组件布局
添加收货地址的本质是一个表单填写过程,需要包含收货人姓名、手机号、省市区选择、详细地址、是否默认地址等字段,我们先设计页面的基本结构,使用Uniapp提供的组件搭建UI。
add-address.vue模板代码:
<template>
<view class="add-address-container">
<view class="form-wrapper">
<!-- 收货人姓名 -->
<view class="form-item">
<text class="label">收货人</text>
<input
type="text"
v-model="form.name"
placeholder="请输入收货人姓名"
maxlength="20"
@blur="validateName"
/>
<text v-if="errors.name" class="error-text">{{ errors.name }}</text>
</view>
<!-- 手机号 -->
<view class="form-item">
<text class="label">手机号</text>
<input
type="number"
v-model="form.phone"
placeholder="请输入手机号"
maxlength="11"
@blur="validatePhone"
/>
<text v-if="errors.phone" class="error-text">{{ errors.phone }}</text>
</view>
<!-- 省市区选择 -->
<view class="form-item" @click="showPicker = true">
<text class="label">所在地区</text>
<view class="picker-value">
{{ form.region || '请选择省市区' }}
<text class="arrow">></text>
</view>
</view>
<!-- 详细地址 -->
<view class="form-item">
<text class="label">详细地址</text>
<textarea
v-model="form.detail"
placeholder="请输入详细地址(街道、门牌号等)"
maxlength="100"
@blur="validateDetail"
></textarea>
<text v-if="errors.detail" class="error-text">{{ errors.detail }}</text>
</view>
<!-- 默认地址 -->
<view class="form-item">
<text class="label">设为默认地址</text>
<switch
:checked="form.isDefault"
@change="handleDefaultChange"
color="#fa2c19"
/>
</view>
</view>
<!-- 提交按钮 -->
<view class="submit-btn" @click="submitForm">保存地址</view>
<!-- 省市区选择器 -->
<picker
mode="region"
:value="regionArray"
@change="onRegionChange"
@cancel="showPicker = false"
v-if="showPicker"
>
<view class="picker-mask"></view>
</picker>
</view>
</template>
脚本部分:
<script>
export default {
data() {
return {
form: {
name: '',
phone: '',
region: '',
detail: '',
isDefault: false
},
errors: {
name: '',
phone: '',
detail: ''
},
showPicker: false,
regionArray: []
}
},
methods: {
// 验证收货人姓名
validateName() {
if (!this.form.name.trim()) {
this.errors.name = '请输入收货人姓名';
return false;
}
if (this.form.name.length < 2) {
this.errors.name = '姓名至少2个字符';
return false;
}
this.errors.name = '';
return true;
},
// 验证手机号
validatePhone() {
const phoneRegex = /^1[3-9]\d{9}$/;
if (!this.form.phone) {
this.errors.phone = '请输入手机号';
return false;
}
if (!phoneRegex.test(this.form.phone)) {
this.errors.phone = '请输入正确的手机号';
return false;
}
this.errors.phone = '';
return true;
},
// 验证详细地址
validateDetail() {
if (!this.form.detail.trim()) {
this.errors.detail = '请输入详细地址';
return false;
}
if (this.form.detail.length < 5) {
this.errors.detail = '详细地址至少5个字符';
return false;
}
this.errors.detail = '';
return true;
},
// 处理默认地址切换
handleDefaultChange(e) {
this.form.isDefault = e.detail.value;
},
// 省市区选择变化
onRegionChange(e) {
this.regionArray = e.detail.value;
this.form.region = this.regionArray.join(' ');
this.showPicker = false;
},
// 提交表单
submitForm() {
const isNameValid = this.validateName();
const isPhoneValid = this.validatePhone();
const isDetailValid = this.validateDetail();
if (!isNameValid || !isPhoneValid || !isDetailValid) {
uni.showToast({
title: '请检查表单信息',
icon: 'none'
});
return;
}
// 模拟保存到本地存储
const addressList = uni.getStorageSync('addressList') || [];
const newAddress = {
...this.form,
id: Date.now(),
createTime: new Date().toISOString()
};
addressList.push(newAddress);
uni.setStorageSync('addressList', addressList);
uni.showToast({
title: '地址保存成功',
icon: 'success'
});
// 返回上一页
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
}
}
</script>
样式设计:
<style lang="scss">
.add-address-container {
min-height: 100vh;
background-color: #f5f5f5;
padding: 20rpx;
.form-wrapper {
background-color: #fff;
border-radius: 12rpx;
padding: 30rpx;
margin-bottom: 30rpx;
.form-item {
display: flex;
align-items: center;
min-height: 100rpx;
border-bottom: 1rpx solid #eee;
position: relative;
.label {
width: 160rpx;
font-size: 28rpx;
color: #333;
flex-shrink: 0;
}
input, textarea {
flex: 1;
font-size: 28rpx;
color: #333;
padding: 10rpx 0;
}
textarea {
min-height: 120rpx;
padding: 10rpx 0;
}
.picker-value {
flex: 1;
font-size: 28rpx;
color: #666;
display: flex;
align-items: center;
.arrow {
margin-left: 10rpx;
color: #999;
font-size: 24rpx;
}
}
.error-text {
position: absolute;
right: 0;
bottom: -20rpx;
font-size: 24rpx;
color: #fa2c19;
}
}
}
.submit-btn {
background-color: #fa2c19;
color: #fff;
text-align: center;
padding: 24r