今天测试代码,发现经常获取不到用户位置,原来是顺序问题,显现出我对执行时机还是没有很熟练。
需求背景
需求是这样:用户手机端定位自己位置,上报自己所在位置的路况信息。
例如路上有树歪了,那么就可以掏出手机,定位自己所在位置并填写一些描述后上传到服务器,供后台人员核实。
关于定位:默认显示用户位置,如果定位用户位置失败,则使用默认位置INIT_LAT,INIT_LNG
问题显现
目前的问题是定位后会闪一下使用默认的位置。
这是我的代码(错误代码)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import { Component, Vue, Watch } from 'vue-property-decorator'; import { getPosDesc, getUserLocation } from '@/plugins/map' import { INIT_LAT, INIT_LNG } from '@/config/map'
@Component export default class PageReport extends Vue { latitude = INIT_LAT longitude = INIT_LNG currentPosDesc = '定位中...' ctx = null
async mounted () { const _ctx = uni.createMapContext('report-map') this.ctx= _ctx
await this.move2MyPosition() } async move2MyPosition() { const _ctx = this.ctx; if (!_ctx) return; uni.showLoading({ title: '定位中...' }) const userPosition = await getUserLocation() _ctx.moveToLocation({ latitude: userPosition?.latitude, longitude: userPosition?.longitude }) this.latitude = userPosition?.latitude this.longitude = userPosition?.longitude uni.hideLoading() }
@Watch('latitude', { immediate:true }) async onPositionChange(val) { const { latitude, longitude } = this const address = await getPosDesc({lat: latitude, lng: longitude}) this.currentPosDesc = address }
mapChange(e) { this.ctx?.getCenterLocation({ success: (res)=> { this.latitude = res.latitude this.longitude = res.longitude } }) } }
|
上面代码问题很多,讲主要问题,关于需求上面描述的获取位置逻辑,首先是获取用户位置,获取失败再使用默认位置。
而我写的是默认使用默认位置,在组件挂载后获取用户位置。
这里很有可能(极大可能)出现一种情况:
时机1:开始获取默认位置
时机2:开始获取用户位置
时机3:用户位置获取成功,将定位信息显示为用户位置
时机4:此时默认位置获取成功,默认位置信息覆盖用户位置,此时显示默认位置。
也就是说,默认位置结果到来时机晚于用户位置,导致即使用户位置获取成功也仍然显示默认位置。
对此,我的修复代码是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| import { Component, Vue, Watch } from 'vue-property-decorator'; import { getPosDesc, getUserLocation } from '@/plugins/map' import { INIT_LAT, INIT_LNG } from '@/config/map'
@Component export default class PageReport extends Vue { latitude = null longitude = null currentPosDesc = '定位中...' ctx = null
async mounted () { const _ctx = uni.createMapContext('report-map') this.ctx= _ctx } async onShow(){ await this.move2MyPosition() } async move2MyPosition() { let _ctx = this.ctx; if (!_ctx) { _ctx = uni.createMapContext('report-map') this.ctx= _ctx } uni.showLoading({ title: '定位中...' }) try{ const userPosition=await getUserLocation() _ctx.moveToLocation({ latitude: userPosition?.latitude, longitude: userPosition?.longitude }) this.latitude = userPosition?.latitude this.longitude = userPosition?.longitude }catch (e){ console.log('error',e) this.latitude = INIT_LAT this.longitude = INIT_LNG }finally { uni.hideLoading() } }
@Watch('latitude', ) async onPositionChange(val) { const { latitude, longitude } = this const address = await getPosDesc({lat: latitude, lng: longitude}) this.currentPosDesc = address }
mapChange(e) { this.ctx?.getCenterLocation({ success: (res)=> { this.latitude = res.latitude this.longitude = res.longitude } }) } }
|
组件数据latitude
,longitude
不再首次赋值默认位置,初始状态应为null
获取用户位置不再从组件挂载时执行mounted
,而是页面展示时执行onShow
获取用户位置时,因为是从onShow
时执行,地图上下文ctx
有两种状态:
- 未执行过
mounted
(第一次打开页面),ctx === null
,此时应创建MapContext
- 执行过
mounted
(第二次打开页面),ctx === MapContext
,此时直接使用ctx
在获取用户位置时,有两种结果:
- 获取位置成功,直接赋值经纬度
latitude
,longitude
为用户位置
- 获取用户位置失败(原因可能是用户未开启定位权限等),赋值默认位置。
获取位置描述不再从组件执行顺序中默认执行,而是等待第一次位置坐标结果到来时获取描述。
结果
此时问题解决:
这里发现显示中心位置的小把手没了,原因在于定位问题,同时为map
和cover-image
添加v-if
即可
1 2 3 4 5 6 7 8 9 10 11 12 13
| <view class="map-wrap"> <map id="report-map" v-if="longitude&&latitude" show-location :markers="markers" @regionchange="mapChange" class="tencent-map" :latitude="latitude" :longitude="longitude"> <cover-view class="location-btn" @click="move2MyPosition"> <cover-image @click="move2MyPosition" src="/static/icon/report/location.png" class="icon" mode="widthFix" /> </cover-view> </map> <cover-image v-if="longitude&&latitude" class="current-site-icon" src="/static/icon/report/choice-marker.png"/> <view>
|