uniapp —— 配合腾讯地图实现小程序自动定位

先解释一下为什么要用腾讯地图实现自动定位

原因:uniapp可以通过uni.getLocation获取用户定位,但是获取到的定位没有中文地址,所以我们需要通过第三方SDK例如高德地图或者腾讯地图来获取中文定位信息。
官方描述

零、事前准备

去腾讯地图开发者平台:《传送地址》

  1. 注册开发者开发账号,创建应用,添加模块key值(这个key值有用,相当于用户标识):
    创建应用添加key值
  2. 下载腾讯地图小程序SDK
    下载SDK
    下载SDK
  3. 引入代码:
    引入代码

一、列举实现步骤

  1. 进入小程序,判断用户本地是否存在定位数据
  2. 若无定位数据则询问用户是否授权定位信息
  3. 若用户拒绝则等待用户手动选择定位

二、先看效果

进入小程序之后,询问用户是否同意授权位置信息:
询问用户
同意之后:
同意之后
储存的数据(其实还有很多,只不过是取了需要的部分储存下来):
储存的数据

三、上代码

这里是封装成了组件,因为在很多地方都有用到:

<template>
	<view>
	    // 使用 uniapp 的 picker 内置组件供用户手动选择定位
	    // u-icon 是 uview 组件库的图标组件
		<picker mode="region" @change="handlePosition">
			<view class="search-map">
				<u-icon name="map" size="23" color="#fff"></u-icon>
				<text class="search-text">{{position || '地区'}}</text>
			</view>
		</picker>
	</view>
</template>

<script>
	/**
	 * 引入腾讯地图微信小程序SDK
	 */
	import QQMapWX from '@/utils/map/qqmap-wx-jssdk.js'
	export default {
		name:"location",
		mounted() {
			// 进入小程序调用授权接口,获取用户当前定位
			if (!uni.getStorageSync('located')) this.getLocation()
		},
		data() {
			return {
				locationInfo: {}, // 用于存储获取得到的数据
				position: uni.getStorageSync('location').district // 这里想要渲染省还是市还是区的数据都可以,看你业务需求
			};
		},
		methods: {
			/**
			 * 向父组件传递数据
			 * */
			toParent() {
				this.$emit('watchPosition', {data: this.locationInfo})
			},
			/**
			 * 用户手动选择定位
			 * @e picker获取得到的参数
			 * */
			handlePosition(e) {
				this.position = e.detail.value[2]
				this.locationInfo.province = e.detail.value[0]
				this.locationInfo.city = e.detail.value[1]
				this.locationInfo.district = e.detail.value[2]
				this.mapBack(e.detail.value[0], e.detail.value[1])
				this.toParent()
			},
			/**
			 * 获取用户当前定位
			 */
			getLocation() {
				let that = this
				// 向用户发起授权请求,弹框提示
				uni.authorize({
					// 获取用户定位信息
					scope: "scope.userLocation",
					// 用户同意授权执行
					success() {
						// 引入腾讯地图API,实例化核心类
						let qqMapSdk = new QQMapWX({
							// 填入你上面申请的应用key值
							key: '你的key值'
						})
						// 获取位置信息
						uni.getLocation({
							type: 'wgs84',
							success(result) {
								// 逆地址解析方法
								qqMapSdk.reverseGeocoder({
									location: {
										latitude: result.latitude,
										longitude: result.longitude
									},
									success(res) {
										that.position = res.result.ad_info.district
										that.locationInfo.province = res.result.ad_info.province
										that.locationInfo.city = res.result.ad_info.city
										that.locationInfo.district = res.result.ad_info.district
										that.mapBack(res.result.ad_info.province, res.result.ad_info.city)
									},
									fail(err) {
										console.log('逆地址解析失败');
									}
								})
							}
						})
					},
					fail(err) {
						uni.showToast({
							icon: 'none',
							title: '注意:需要授权获取定位,否则部分功能将无法使用',
							duration: 2000
						})
					}
				})
			},
			/**
			 * 转换为后端的定位编码
			 * @province 需要转换编码的省份
			 * @city 需要转换编码的城市
			 * */
			mapBack(province, city) {
				let that = this
				const localLocation = JSON.parse(uni.getStorageSync('address'))
				localLocation.map(item => {
					if (item.name == province.substr(0, province.length - 1)) {
						that.locationInfo.province_code = ''
						that.locationInfo.city_code = item.id
					} else {
						item.address.map(items => {
							if (items.name == city.substr(0, city.length - 1)) {
								that.locationInfo.province_code = item.id
								that.locationInfo.city_code = items.id
							}
						})
					}
				})
				// 本地保存定位
				uni.setStorageSync('location', that.locationInfo)
				// 更新全局定位数据
				uni.setStorageSync('located', true)
			}
		}
	}
</script>

<style scoped lang="scss">
.search-map {
	display: flex;
	justify-content: center;
	align-items: center;
	color: white;
	.search-text {
		color:#fff;
		font-size: 24rpx;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}
}
</style>

四、使用场景

自动获取或者是手动获取定位,组件内都会自动渲染获取的地点,不用监听:

<search @inputValue="bindinput" @confirm="bindConfirm">
	<location @watchPosition="watchComPosition" slot="left"></location> // 自动渲染定位
	<picker slot="center" mode="selector" :range="selectArray" @change="bindSelect">
		<view class="search-drop row-c">
			<view class="search-drop-text">{{select == 0 ? '我要买' : '我要卖'}}</view>
			<u-icon color="#fff" name="arrow-down"></u-icon>
		</view>
	</picker>
	<view slot="right" @click="$u.throttle(bindSearch, 3000)" class="row-c">
		<u-icon color="#fff" size="27" name="search"></u-icon>
	</view>
</search>

想要用本地储存的定位数据(uni.getStorageSync('location'))来获取某个地区的商品数据:

async filter() {
	let that = this
	// 取消全部已收藏状态
	this.isSubAll = false
	// 获取本地储存的定位数据
	const cityCode = uni.getStorageSync('location')
	const handleObj = {
		city: cityCode.city_code ? cityCode.city_code : cityCode.province_code,
		cate: that.selected,
		pay_content: that.search,
		time: that.dateNum,
		delivery: that.packNum,
		selltype: that.typeNum,
		page: that.page,
		pagesize: that.pageSize,
		user_id: uni.getStorageSync('userinfo').user_id
	}	
	await purchase(handleObj).then((res) => {
		if (res.statusCode == 200) {
			that.loadingStatus = 'loadmore'
			that.lastPage = res.data.page_info.last_page
			that.total = res.data.page_info.total
			const resultArray = res.data.data
			// 如果有数据
			if (resultArray.length != 0) {
				// 如果是下拉加载,则叠加数据,否则,直接赋值
				if (that.pageFlag) {
					that.pageFlag = false
					that.buyListData = [...that.buyListData, ...resultArray]
				} else {
					that.buyListData = [...resultArray]
				}
				// 数据赋值->深拷贝,并刨除已收藏商品
				that.cacheArray = JSON.parse(JSON.stringify(that.buyListData))
			} else {
				// 如果没有数据,也不是下拉加载,直接赋值为空
				if (!that.pageFlag) {
					that.buyListData = []
					that.cacheArray = []
				}
			}
		}
	})
}

如果用户通过手动选择定位,来获取某个地区的商品数据,则可以通过组件内实现封装好的方法来监听获取的数据和变化:

// 监听子组件手动定位事件
watchComPosition() {
	this.page = 1
	this.filter()
}
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐