小程序调用地图api
uni项目发小程序,调用地图api问题
·
- 在app.json中添加requiredPrivateInfos字段,并声明chooseLocation。
- 同时,确保已经配置了permission字段,以获取用户位置权限。
app.json
"permission": {
"scope.userLocation": {
"desc": "您的位置信息将用于获取发货地址"
}
},
"requiredPrivateInfos": [
"getLocation",
"chooseLocation"
],
address.vue
<script lang="ts">
export default { name: 'AddressList' }
</script>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import type { AddressList } from '@/api/post/model'
import AddressListItem from '@/components/common/AddressListItem.vue'
import { useUserStore } from '@/store/user';
const userStore = useUserStore()
// 获取用户地址
const getUserAddress = async () => {
const data = await userStore.getUserAddressPage()
console.log("用户地址列表", data)
addressList.value = data.records
}
getUserAddress()
// 模拟地址数据,确保地址格式包含街道信息和具体地址
const addressList = ref<Array<AddressList & { id: string; isDefault: boolean }>>([
])
// 弹出层显示状态
const showAddressModal = ref(false);
// 使用普通对象而不是ref对象来存储表单数据
let tempAddressForm: AddressList & { id: string; isDefault: boolean, latitude?: number, longitude?: number } = {
id: '',
name: '',
phone: '',
address: '',
street: '',
provice: '',
area: '',
isDefault: false,
latitude: undefined,
longitude: undefined
}
// 创建响应式的表单数据引用,用于模板绑定
const addressForm = ref({ ...tempAddressForm })
// 重置表单数据
const resetForm = () => {
// 创建全新的对象,避免任何可能的只读问题
tempAddressForm = {
id: '',
name: '',
phone: '',
address: '',
street: '',
provice: '',
area: '',
isDefault: false,
latitude: undefined,
longitude: undefined
}
// 更新响应式引用
addressForm.value = { ...tempAddressForm }
}
// 编辑地址
const handleEdit = (id: string) => {
// 这里应该跳转到编辑页面,传递地址ID
console.log('编辑地址', id)
// 实际应用中应该使用路由跳转
// uni.$u.route({
// url: 'pages/me/addressEdit',
// params: { id }
// })
}
// 删除地址
const handleDelete = async (id: string) => {
// 调用接口删除
const data = await userStore.deletedUserAddress(id);
console.log(data)
// 从列表中移除地址
addressList.value = addressList.value.filter(item => item.id !== id)
console.log('删除地址', id)
}
// 设置默认地址
const handleSetDefault = async (id: string) => {
const res = await userStore.updateUserAddressDefault(id);
console.log(res)
if (res.code === 0) {
// 成功
// 将所有地址的isDefault设置为false
addressList.value.forEach(item => {
item.isDefault = false
})
// 将选中的地址设置为默认
const target = addressList.value.find(item => item.id === id)
if (target) {
target.isDefault = true
}
uni.showToast({
title: res.message
})
} else {
uni.showModal({
title: '提示',
content: res.msg,
showCancel: false
})
}
console.log(res)
}
// 添加新地址
const handleAddAddress = () => {
try {
console.log('添加新地址,调用地图选择功能')
// 重置表单
resetForm()
// 调用uni-app的地图选择API
uni.chooseLocation({
success: (res) => {
try {
console.log('选择地址成功', res)
// 创建一个全新的临时对象
const newAddressData = {
id: Date.now().toString(), // 生成临时ID
name: '', // 需要用户填写
phone: '', // 需要用户填写
address: res.address, // 详细地址
street: res.address.split(' ')[0] || '', // 提取街道信息
provice: res.address.match(/^([^市]+市)?/)?.[1] || '', // 简单提取省份
area: res.address.match(/市([^区]+区)/)?.[1] || '', // 简单提取区县
isDefault: false,
latitude: res.latitude, // 纬度
longitude: res.longitude // 经度
}
console.log('准备更新的地址数据:', newAddressData)
// 更新临时表单数据
tempAddressForm = { ...newAddressData }
// 更新响应式引用 - 创建全新的对象避免只读问题
addressForm.value = { ...tempAddressForm }
console.log('更新后的地址信息:', addressForm.value)
// 显示地址表单弹出层
showAddressModal.value = true
} catch (innerError) {
console.error('处理地址数据时发生错误:', innerError)
uni.showToast({
title: '处理地址信息失败',
icon: 'none',
duration: 2000
})
}
},
fail: (err) => {
console.error('选择地址失败', err)
// 如果是用户取消操作,不做任何提示
if (err.errMsg.indexOf('cancel') >= 0) {
return
}
// 权限被拒绝,提示用户
if (err.errMsg.indexOf('auth deny') >= 0) {
uni.showModal({
title: '提示',
content: '需要您授权位置权限才能选择地址',
success: (res) => {
if (res.confirm) {
// 引导用户打开授权设置
uni.openSetting()
}
}
})
} else {
uni.showToast({
title: '获取地址失败: ' + err.errMsg,
icon: 'none',
duration: 2000
})
}
}
})
} catch (error) {
console.error('handleAddAddress函数执行错误:', error)
// 显示详细错误提示给用户
const errorMessage = error instanceof Error ? error.message : '未知错误'
console.log('错误详情:', { name: error.name, message: error.message, stack: error.stack })
uni.showToast({
title: '操作失败: ' + errorMessage,
icon: 'none',
duration: 3000
})
}
}
// 保存新地址
const handleSaveAddress = () => {
try {
// 验证表单
if (!addressForm.value.name) {
uni.showToast({ title: '请输入收货人姓名', icon: 'none' })
return
}
if (!addressForm.value.phone) {
uni.showToast({ title: '请输入收货人电话', icon: 'none' })
return
}
// 创建一个全新的地址对象,避免引用问题
const addressToAdd = { ...addressForm.value }
// 如果设置为默认地址,取消其他地址的默认状态
if (addressToAdd.isDefault) {
addressList.value.forEach(item => {
item.isDefault = false
})
}
// 添加新地址到列表
addressList.value.push(addressToAdd)
// 关闭弹出层
showAddressModal.value = false
// 重置表单
resetForm()
// 提示保存成功
uni.showToast({ title: '添加成功', icon: 'success' })
} catch (error) {
console.error('保存地址时发生错误:', error)
uni.showToast({
title: '保存失败,请重试',
icon: 'none',
duration: 2000
})
}
}
// 取消添加地址
const handleCancelAddress = () => {
showAddressModal.value = false
// 重置表单,避免下次打开时有残留数据
resetForm()
}
// 切换默认地址状态
const toggleDefaultAddress = () => {
try {
// 创建新对象来更新isDefault状态,避免直接修改只读属性
const updatedForm = { ...addressForm.value }
updatedForm.isDefault = !updatedForm.isDefault
// 更新响应式引用
addressForm.value = updatedForm
} catch (error) {
console.error('切换默认地址状态失败:', error)
}
}
// 地图标记点击事件
const handleMarkerTap = (e: any) => {
console.log('地图标记点击', e)
}
// 地图区域变化事件
const handleRegionChange = (e: any) => {
console.log('地图区域变化', e)
// 可以在这里处理地图拖拽、缩放等操作
}
onMounted(() => {
// 这里可以调用API获取用户的地址列表
// 模拟API请求
console.log('获取地址列表')
})
</script>
<template>
<!-- 非H5平台显示状态栏 -->
<!-- #ifndef H5 -->
<status-bar />
<!-- #endif -->
<view class="address-list-container">
<!-- 地址列表 -->
<view class="address-content" v-if="addressList.length > 0">
<view v-for="item in addressList" :key="item.id">
<AddressListItem :data="item" @edit="handleEdit" @delete="handleDelete" @setDefault="handleSetDefault" />
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-else>
<text class="empty-text">暂无收货地址</text>
</view>
<!-- 添加新地址按钮 -->
<view class="add-address-btn" @click="handleAddAddress">
<text>+ 添加新地址</text>
</view>
<!-- 地址表单弹出层 -->
<uni-popup ref="popup" v-model="showAddressModal" type="bottom" :mask-click="false">
<view class="address-form-container">
<view class="form-header">
<text class="cancel-btn" @click="handleCancelAddress">取消</text>
<text class="title">新增收货地址</text>
<text class="save-btn" @click="handleSaveAddress">保存</text>
</view>
<map style="width: 100%; height: 300px;" scale="14" />
<view class="form-content">
<!-- 所在地区 -->
<view class="form-item">
<text class="label">所在地区</text>
<view class="area-info">
<text>{{ addressForm.provice }}{{ addressForm.area }}</text>
<view class="default-checkbox" @click="toggleDefaultAddress">
<view class="checkbox-icon" :class="{ checked: addressForm.isDefault }">
<u-icon v-if="addressForm.isDefault" name="success" size="22" color="#fff" />
</view>
<text class="checkbox-text">设为默认</text>
</view>
</view>
</view>
<!-- 详细地址 -->
<view class="form-item">
<text class="label">详细地址</text>
<input class="input" v-model="addressForm.address" placeholder="请输入详细地址" />
</view>
<!-- 收货人姓名 -->
<view class="form-item">
<text class="label">收货人</text>
<input class="input" v-model="addressForm.name" placeholder="请输入收货人姓名" />
</view>
<!-- 手机号码 -->
<view class="form-item">
<text class="label">手机号码</text>
<input class="input" v-model="addressForm.phone" type="number" placeholder="请输入手机号码" maxlength="11" />
</view>
</view>
</view>
</uni-popup>
</view>
</template>
<style lang="scss" scoped>
.address-list-container {
height: 100vh;
width: 100%;
padding-bottom: 20rpx;
.page-header {
padding: 30rpx;
background: #fff;
margin-bottom: 20rpx;
.title {
font-size: 36rpx;
font-weight: 600;
color: #333;
}
}
.address-content {
padding: 0 30rpx;
}
.empty-state {
padding: 100rpx 0;
text-align: center;
.empty-text {
font-size: 28rpx;
color: #999;
}
}
.add-address-btn {
margin: 40rpx 30rpx 0;
padding: 25rpx 0;
background: #3FBDFF;
color: #fff;
font-size: 32rpx;
text-align: center;
border-radius: 10rpx;
&:active {
background: #94bcff;
}
}
// 地址表单弹出层样式
.address-form-container {
background: #fff;
border-radius: 20rpx 20rpx 0 0;
.form-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
.cancel-btn,
.save-btn {
font-size: 32rpx;
color: #999;
}
.save-btn {
color: #3FBDFF;
}
.title {
font-size: 34rpx;
font-weight: 600;
color: #333;
}
}
.form-content {
padding: 30rpx;
.form-item {
margin-bottom: 40rpx;
.label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 15rpx;
}
.input {
width: 100%;
height: 88rpx;
background: #f5f5f5;
border-radius: 10rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #333;
box-sizing: border-box;
}
.area-info {
display: flex;
justify-content: space-between;
align-items: center;
height: 88rpx;
background: #f5f5f5;
border-radius: 10rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #333;
}
.default-checkbox {
display: flex;
align-items: center;
.checkbox-icon {
width: 32rpx;
height: 32rpx;
border: 2rpx solid #ccc;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10rpx;
&.checked {
background: #3FBDFF;
border-color: #3FBDFF;
}
}
.checkbox-text {
font-size: 28rpx;
color: #666;
}
}
}
}
}
}
</style>
更多推荐


所有评论(0)