333 lines
7.4 KiB
Vue
333 lines
7.4 KiB
Vue
<template>
|
|
<view class="map_page">
|
|
<uni-nav-bar
|
|
left-icon="back"
|
|
@clickLeft="back"
|
|
statusBar
|
|
fixed
|
|
backgroundColor="transparent"
|
|
>
|
|
<template slot="right">
|
|
<u-button type="primary" @click="confirm">确定</u-button>
|
|
</template>
|
|
</uni-nav-bar>
|
|
<map
|
|
ref="map"
|
|
class="map_containter"
|
|
:latitude="mapCenter.lat"
|
|
:longitude="mapCenter.lng"
|
|
:scale="scale"
|
|
@regionchange="onMapRegionChange"
|
|
show-location
|
|
>
|
|
<!-- 中心点marker -->
|
|
<cover-view class="center_marker">
|
|
<cover-image src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3E%3Ccircle cx='15' cy='15' r='12' fill='%23FF4444' opacity='0.8'/%3E%3Ccircle cx='15' cy='15' r='8' fill='%23FFFFFF'/%3E%3C/svg%3E"></cover-image>
|
|
</cover-view>
|
|
</map>
|
|
|
|
<!-- 加载提示 -->
|
|
<view v-if="isLoading" class="loading_overlay">
|
|
<uni-load-more status="loading" content-text="加载中"></uni-load-more>
|
|
</view>
|
|
|
|
<!-- 地址信息展示 -->
|
|
<view class="address_info">
|
|
<view class="address_title">位置信息</view>
|
|
<view class="address_text">{{ currentAddress || '加载中...' }}</view>
|
|
<view class="coordinates">
|
|
经度: {{ mapCenter.lng.toFixed(6) }} | 纬度: {{ mapCenter.lat.toFixed(6) }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
// 地图中心点
|
|
mapCenter: {
|
|
lng: 116.397128,
|
|
lat: 39.916527
|
|
},
|
|
// 初始中心点(用于比较)
|
|
initialCenter: {
|
|
lng: 116.397128,
|
|
lat: 39.916527
|
|
},
|
|
// 地图缩放级别
|
|
scale: 16,
|
|
// 当前地址
|
|
currentAddress: '北京市朝阳区',
|
|
// 选中的位置数据
|
|
selectedPoint: null,
|
|
// 是否正在加载
|
|
isLoading: false,
|
|
// 地图对象
|
|
mapContext: null,
|
|
// 地址解析延迟器
|
|
addressTimer: null,
|
|
// 高德地图API key(需要替换为实际的key)
|
|
aMapKey: ''
|
|
}
|
|
},
|
|
mounted() {
|
|
this.initMap();
|
|
},
|
|
beforeDestroy() {
|
|
// 清理定时器
|
|
if (this.addressTimer) {
|
|
clearTimeout(this.addressTimer);
|
|
}
|
|
},
|
|
methods: {
|
|
/**
|
|
* 初始化地图
|
|
*/
|
|
initMap() {
|
|
this.mapContext = uni.createMapContext('map', this);
|
|
// 获取当前位置权限
|
|
this.getCurrentLocation();
|
|
},
|
|
|
|
/**
|
|
* 获取当前位置
|
|
*/
|
|
getCurrentLocation() {
|
|
uni.getLocation({
|
|
type: 'gcj02',
|
|
success: (res) => {
|
|
this.mapCenter = {
|
|
lng: res.longitude,
|
|
lat: res.latitude
|
|
};
|
|
this.initialCenter = {
|
|
lng: res.longitude,
|
|
lat: res.latitude
|
|
};
|
|
// 获取地址
|
|
this.getAddressFromCoordinates(res.longitude, res.latitude);
|
|
},
|
|
fail: (err) => {
|
|
// 权限拒绝或失败,使用默认位置
|
|
console.log('获取位置失败,使用默认位置', err);
|
|
this.getAddressFromCoordinates(this.mapCenter.lng, this.mapCenter.lat);
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* 地图区域变化时触发
|
|
*/
|
|
onMapRegionChange(e) {
|
|
if (e.type === 'end') {
|
|
// 获取地图中心点坐标
|
|
this.mapContext.getCenterLocation({
|
|
success: (res) => {
|
|
this.mapCenter = {
|
|
lng: res.longitude,
|
|
lat: res.latitude
|
|
};
|
|
// 延迟获取地址,避免频繁调用
|
|
this.debounceGetAddress();
|
|
},
|
|
fail: (err) => {
|
|
console.log('获取地图中心点失败', err);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 防抖获取地址
|
|
*/
|
|
debounceGetAddress() {
|
|
if (this.addressTimer) {
|
|
clearTimeout(this.addressTimer);
|
|
}
|
|
this.addressTimer = setTimeout(() => {
|
|
this.getAddressFromCoordinates(this.mapCenter.lng, this.mapCenter.lat);
|
|
}, 500);
|
|
},
|
|
|
|
/**
|
|
* 根据坐标获取地址(使用高德地图API)
|
|
*/
|
|
getAddressFromCoordinates(lng, lat) {
|
|
// 方法1:使用高德地图逆地理编码API
|
|
// 注意:需要在高德地图申请API key
|
|
const aMapUrl = `https://restapi.amap.com/v3/geocode/regeo?location=${lng},${lat}&key=YOUR_AMAP_KEY`;
|
|
|
|
// 这里使用本地模拟,实际项目中应该调用真实API
|
|
this.simulateAddressLookup(lng, lat);
|
|
},
|
|
|
|
/**
|
|
* 模拟地址查询(实际项目应调用真实的地理编码API)
|
|
*/
|
|
simulateAddressLookup(lng, lat) {
|
|
// 简单的地址模拟逻辑
|
|
const addresses = [
|
|
'北京市朝阳区建国路88号',
|
|
' 北京市东城区天安门广场',
|
|
'上海市浦东新区陆家嘴环路1088号',
|
|
'深圳市福田区中心区',
|
|
'杭州市上城区武林路'
|
|
];
|
|
|
|
// 根据坐标返回对应的地址(这里是随机模拟)
|
|
const index = Math.floor((lng + lat) % addresses.length);
|
|
this.currentAddress = addresses[index] || `经度: ${lng.toFixed(6)}, 纬度: ${lat.toFixed(6)}`;
|
|
},
|
|
|
|
/**
|
|
* 确定位置按钮点击
|
|
*/
|
|
confirm() {
|
|
const _this = this;
|
|
|
|
// 验证是否有有效的位置数据
|
|
if (!this.mapCenter.lng || !this.mapCenter.lat) {
|
|
uni.showToast({
|
|
title: '位置数据无效',
|
|
icon: 'none'
|
|
});
|
|
return;
|
|
}
|
|
|
|
// 保存选中的位置
|
|
_this.selectedPoint = {
|
|
lng: this.mapCenter.lng,
|
|
lat: this.mapCenter.lat,
|
|
address: this.currentAddress
|
|
};
|
|
|
|
// 通过事件通道返回数据给父页面
|
|
const eventChannel = this.getOpenerEventChannel();
|
|
eventChannel.emit('onConfirm', {
|
|
lng: this.mapCenter.lng,
|
|
lat: this.mapCenter.lat,
|
|
address: this.currentAddress
|
|
});
|
|
|
|
// 显示成功提示
|
|
uni.showToast({
|
|
title: '位置已确定',
|
|
icon: 'success',
|
|
duration: 1500
|
|
});
|
|
|
|
// 延迟返回,让用户看到提示
|
|
setTimeout(() => {
|
|
uni.navigateBack();
|
|
}, 1500);
|
|
},
|
|
|
|
/**
|
|
* 返回上一页
|
|
*/
|
|
back() {
|
|
uni.navigateBack();
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.map_page {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100vh;
|
|
width: 100vw;
|
|
background: #fff;
|
|
position: relative;
|
|
overflow: hidden;
|
|
|
|
.map_containter {
|
|
flex: 1;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
// 中心点marker样式
|
|
.center_marker {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
width: 30px;
|
|
height: 30px;
|
|
margin-left: -15px;
|
|
margin-top: -15px;
|
|
z-index: 100;
|
|
pointer-events: none;
|
|
|
|
cover-image {
|
|
width: 100%;
|
|
height: 100%;
|
|
animation: bounce 1.5s ease-in-out infinite;
|
|
}
|
|
}
|
|
|
|
// 加载覆盖层
|
|
.loading_overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: rgba(0, 0, 0, 0.3);
|
|
z-index: 200;
|
|
}
|
|
|
|
// 地址信息展示框
|
|
.address_info {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background: rgba(255, 255, 255, 0.95);
|
|
backdrop-filter: blur(10px);
|
|
padding: 12px 16px;
|
|
z-index: 99;
|
|
border-top: 1px solid #e5e5e5;
|
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
|
|
|
|
.address_title {
|
|
font-size: 12px;
|
|
color: #999;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.address_text {
|
|
color: #333;
|
|
font-size: 14px;
|
|
line-height: 1.5;
|
|
word-break: break-word;
|
|
margin-bottom: 6px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.coordinates {
|
|
color: #666;
|
|
font-size: 12px;
|
|
font-family: monospace;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 跳动动画
|
|
@keyframes bounce {
|
|
0%, 100% {
|
|
transform: scale(1);
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
transform: scale(1.2);
|
|
opacity: 0.8;
|
|
}
|
|
}
|
|
</style> |