uniapp 开发微信小程序,获取经纬度并且转化详细地址(单独封装版本)

发布于:2025-08-16 ⋅ 阅读:(13) ⋅ 点赞:(0)

1、单独抽离封装

// 腾讯地图SDK引入(需提前下载qqmap-wx-jssdk.min.js文件)
// 注意:使用前需在微信公众平台配置request合法域名https://apis.map.qq.com
var QQMapWX = require('@/libs/qqmap-wx-jssdk.min.js')

// 高德地图SDK引入(需提前下载amap-wx.130.js文件)
// 注意:使用前需配置高德域名白名单https://restapi.amap.com
import amap from '@/libs/amap-wx.130.js';

/**
 * 地图服务配置常量
 * 建议通过构建工具注入环境变量,避免硬编码
 * AMAP_KEY:高德开发者密钥(需到lbs.amap.com申请)
 * QQMAP_KEY:腾讯地图开发者密钥(需到lbs.qq.com申请)
 */
const MAP_CONFIG = {
	AMAP_KEY: '', // 您的高德地图Key 
	QQMAP_KEY: '' // 您的腾讯地图Key
}

/**
 * 定位服务核心类
 * 功能:封装高德/腾讯地图的定位和逆地理编码能力
 * 特点:
 * 1. 双地图服务支持(自动根据配置初始化)
 * 2. 完整的权限控制流程
 * 3. 统一的数据格式返回
 */
export default class LocationService {
	constructor() {
		this.amapPlugin = null // 高德地图实例
		this.qqmapsdk = null // 腾讯地图实例
		this._initSDK() // 自动初始化SDK
	}

	/**
	 * 初始化地图SDK(私有方法)
	 * 注意:会根据MAP_CONFIG配置自动初始化可用SDK
	 * 高德地图需额外配置Geocoder插件用于逆地理编码
	 */
	_initSDK() {
		// 高德地图初始化(需同时满足SDK存在且配置了有效KEY)
		if (typeof amap !== 'undefined' && MAP_CONFIG.AMAP_KEY) {
			this.amapPlugin = new amap.AMapWX({
				key: MAP_CONFIG.AMAP_KEY,
				// plugin: ['AMap.Geocoder'] // 必须添加地理编码插件
			})
		}

		// 腾讯地图初始化(需同时满足SDK存在且配置了有效KEY)
		if (typeof QQMapWX !== 'undefined' && MAP_CONFIG.QQMAP_KEY) {
			this.qqmapsdk = new QQMapWX({
				key: MAP_CONFIG.QQMAP_KEY
			})
		}
	}



	/**
	 * 统一权限检查流程(私有方法)
	 * 三阶段处理:
	 * 1. 检查已有权限
	 * 2. 无权限时请求授权(每次拒绝后下次仍会触发系统弹窗)
	 * 3. 授权被拒时引导用户去设置页
	 */
	async _checkPermission() {
		return new Promise((resolve, reject) => {
			uni.getSetting({
				success: (res) => {
					// 已有权限直接通过
					if (res.authSetting['scope.userLocation'] === true) {
						resolve(true)
					} else {
						// 1. 先请求授权
						// uni.authorize:用于‌首次请求权限‌,弹窗询问用户是否允许获取位置
						uni.authorize({
							scope: 'scope.userLocation',
							success: () => resolve(true),
							fail: (err) => {
								// 引导去设置页(不阻止后续再次触发系统弹窗)
								this._showPermissionModal().finally(() => {
									reject(new Error('PERMISSION_DENIED'))
								})
							}
						})
					}
				},
				fail: reject
			})
		})
	}

	/**
	 * 显示权限引导弹窗(私有方法)
	 * 增强功能:用户从设置页返回后自动尝试获取定位
	 */
	_showPermissionModal() {
		return new Promise((resolve) => {
			uni.showModal({
				title: '权限提示',
				content: '需要位置权限才能获取定位信息',
				confirmText: '去设置',
				success: (res) => {
					if (res.confirm) {
						uni.openSetting({
							success: (settingRes) => {
								// 设置页返回后检查权限状态
								if (settingRes.authSetting['scope.userLocation']) {
									resolve(true) // 权限已开启
								} else {
									resolve(false) // 用户未开启权限
								}
							},
							fail: () => resolve(false)
						})
					} else {
						resolve(false)
					}
				}
			})
		})
	}

	/**
	 * 获取基础坐标(核心方法)
	 * 增强功能:支持从设置页返回后自动获取坐标
	 * @param {Object} options 配置项
	 *        - altitude: 是否获取海拔高度(默认false)
	 *        - highAccuracy: 是否启用高精度模式(耗电增加)
	 * @returns {Promise} 包含经纬度等信息的Promise
	 */
	async getCoordinates(options = {}) {
		try {
			// 检查权限(包含引导设置流程)
			const hasPermission = await this._checkPermission()
			if (!hasPermission) throw new Error('PERMISSION_DENIED')

			return new Promise((resolve, reject) => {
				// 2. 授权成功后获取高精度坐标
				// uni.getLocation:‌实际获取坐标‌,需在权限通过后调用
				uni.getLocation({
					// wgs84:国际标准GPS坐标系(原始经纬度数据)
					// gcj02:中国国测局坐标系(高德/腾讯地图专用)

					type: 'gcj02',
					altitude: !!options.altitude,
					isHighAccuracy: !!options.highAccuracy, //高精度模式(isHighAccuracy:true)会增加功耗,建议按需使用
					success: (res) => {
						resolve({
							longitude: res.longitude,
							latitude: res.latitude,
							altitude: res.altitude || null,
							accuracy: res.accuracy,
							verticalAccuracy: res.verticalAccuracy || null
						})
					},
					fail: (err) => {
						console.log('err-----授权', err)
						// 特殊处理用户从设置页返回的情况
						if (err.errMsg.includes('auth deny')) {
							this.getCoordinates(options).then(resolve).catch(reject)
						} else {
							reject((err))
						}
					}
				})
			})
		} catch (err) {
			throw (err)
		}
	}




	/**
	 * 获取高德地图地址信息(核心方法)
	 * 流程:获取坐标 -> 调用高德逆地理编码接口
	 * 注意:需提前配置高德域名白名单
	 */
	async getAMapAddress(options = {}) {
		if (!this.amapPlugin) {
			throw new Error('AMAP_SDK_NOT_INIT')
		}

		try {
			// 先获取基础坐标
			const coords = await this.getCoordinates(options)

			return new Promise((resolve, reject) => {
				// 调用高德逆地理编码接口
				this.amapPlugin.getRegeo({
					location: `${coords.longitude},${coords.latitude}`,
					success: (data) => {
						resolve(this._formatAMapData(data, coords))
					},
					fail: (err) => reject(err)
				})
			})
		} catch (err) {
			throw (err)
		}
	}

	/**
	 * 获取腾讯地图地址信息(核心方法)
	 * 流程:获取坐标 -> 调用腾讯逆地理编码接口
	 * 注意:需提前配置腾讯地图域名白名单
	 */
	async getQQMapAddress(options = {}) {
		if (!this.qqmapsdk) {
			throw new Error('QQMAP_SDK_NOT_INIT')
		}

		try {
			// 先获取基础坐标
			const coords = await this.getCoordinates(options)

			return new Promise((resolve, reject) => {
				// 调用腾讯逆地理编码接口
				this.qqmapsdk.reverseGeocoder({
					location: {
						latitude: coords.latitude,
						longitude: coords.longitude
					},
					get_poi: options.includePOI || false, // 是否返回周边POI信息
					success: (res) => {
						resolve(this._formatQQMapData(res, coords))
					},
					fail: (err) => reject(err)
				})
			})
		} catch (err) {
			throw (err)
		}
	}

	// 新增:通过坐标获取高德地址信息
	async getAMapByCoordinates(lng, lat, options = {}) {
		if (!this.amapPlugin) throw new Error('AMAP_SDK_NOT_INIT')
		return new Promise((resolve, reject) => {
			this.amapPlugin.getRegeo({
				location: `${lng},${lat}`,
				success: (data) => resolve(this._formatAMapData(data, {
					longitude: lng,
					latitude: lat
				})),
				fail: reject
			})
		})
	}

	// 新增:通过坐标获取腾讯地址信息
	async getQQMapByCoordinates(lng, lat, options = {}) {
		if (!this.qqmapsdk) throw new Error('QQMAP_SDK_NOT_INIT')
		return new Promise((resolve, reject) => {
			this.qqmapsdk.reverseGeocoder({
				location: {
					latitude: lat,
					longitude: lng
				},
				get_poi: options.includePOI || false,
				success: (res) => resolve(this._formatQQMapData(res, {
					longitude: lng,
					latitude: lat
				})),
				fail: reject
			})
		})
	}


	/**
	 * 格式化高德地图返回数据(私有方法)
	 * 统一数据格式,方便业务层使用
	 */
	_formatAMapData(data, coords) {
		console.log('高德地图返回数据', data)
		const firstResult = data[0] || {}
		return firstResult
		//也可以根据具体数据自定义返回
		// return {
		// 	coordinates: coords, // 原始坐标信息
		// 	formattedAddress: firstResult.address || '', // 完整地址
		// 	country: firstResult.country || '',
		// 	province: firstResult.province || '',
		// 	city: firstResult.city || '',
		// 	district: firstResult.district || '',
		// 	street: firstResult.street || '',
		// 	streetNumber: firstResult.streetNumber || '',
		// 	cityCode: firstResult.citycode || '', // 城市编码
		// 	adCode: firstResult.adcode || '', // 区域编码
		// 	poiList: firstResult.poiList || [] // 周边POI列表
		// }
	}

	/**
	 * 格式化腾讯地图返回数据(私有方法)
	 * 统一数据格式,方便业务层使用
	 */
	_formatQQMapData(data, coords) {
		console.log('腾讯地图返回数据-', data)
		const address = data.result || {}
		return address
		//也可以根据具体数据自定义返回
		// return {
		// 	coordinates: coords, // 原始坐标信息
		// 	formattedAddress: address.address || '', // 完整地址
		// 	country: address.address_component?.nation || '',
		// 	province: address.address_component?.province || '',
		// 	city: address.address_component?.city || '',
		// 	district: address.address_component?.district || '',
		// 	street: address.address_component?.street || '',
		// 	streetNumber: address.add
		// }
	}
}

2、使用示例

import LocationService from '@/utils/location.js'
async getAMapAddress() {
	try {
		// 仅仅获取经纬度
		const result = await new LocationService().getCoordinates()
		// 根据高德逆地理编码接口,获取当前经纬度对应的具体地址
		const result = await new LocationService().getAMapAddress()
		// 根据腾讯逆地理编码接口,获取当前经纬度对应的具体地址
		const result = await new LocationService().getQQMapAddress()
		// 根据高德逆地理编码接口,获取传入的经纬度对应的具体地址
		const result = await new LocationService().getAMapByCoordinates('', '')
		// 根据腾讯逆地理编码接口,获取传入的经纬度对应的具体地址
		const result = await new LocationService().getQQMapByCoordinates('', '')
		console.log(result, '经纬度||地址')

	} catch (err) {
		console.log(err)
	}
}

3、前置条件和配置

具体可以查看另一篇文章:
https://blog.csdn.net/weixin_41549971/article/details/149837996?spm=1011.2415.3001.5331

4、效果弹框

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到