Vue2项目中如何接入腾讯地图,无需多说,参照官方文档,很好实现。今天我们要说的,是接入腾讯地图时踩的坑。
接入地图
我们项目中,接入地图的需求是,在新增/编辑活动时,根据用户输入的关键字进行地图定位,从而获取有经纬度坐标的活动举办地点,如下图:
为了实现该需求,写下了如下的伪代码:
<template>
<div ref="mapWrap"style="width:100%;height:280px;" class="mapWrap"></div>
</template>
<script>
export default {
data() {
return {
id: ''
map: null, // 地图对象
infoWindow: null, // 地图信息窗口对象
}
},
activated() {
const query = this.$route.query || {}
this.id = query.id || ''
if(this.id) {
await this.getActivityDetail(this.id)
}
this.initMap()
},
methods: {
initMap() {
this.map = null
this.infoWindow = null
this.mapInit()
},
mapInit() {
// 在获取DOM后操作
this.$nextTick( () => {
if(!this.$refs.mapWrap) { // mapWrap获取不到时,往下走会报错
return
}
// 按官方文档初始化地图
//...
})
},
// 获取活动详情
getActivityDetail(id) {
}
}
}
</script>
没错,地图成功渲染出来了,但在自测过程中,一些隐形的坑也渐渐暴露出来了。
坑一:地图多次渲染
在自测过程中,交替打开新增页面、编辑页面(其实是同一个页面,入口不同而已),然后就出现了地图多次渲染的现象,如下图:
坑二:地图保留了上次操作的痕迹
在自测过程中,还发现了,多次打开新增页面,地图信息窗口等都还保留了上次的操作痕迹,如下图。打开编辑页面时没有这个问题,因为地图信息窗口里的内容是根据接口数据进行回显的。
针对坑一、坑二,排查原因,得知是每打开一次页面,就会追加绘制一个地图,而不是覆盖原来绘制的地图。
所以解决方案是:利用v-if,清除上一个绘制的地图,重绘最新的地图。
然后就加了如下的代码:
<template>
<div ref="mapWrap"style="width:100%;height:280px;" class="mapWrap" v-if="mapShow"></div>
</template>
<script>
export default {
data() {
return {
// ...
mapShow: false, // 新增字段
}
},
methods: {
initMap() {
this.mapShow = false // 新增代码
// ...
},
mapInit() {
// 在获取DOM后操作
this.$nextTick( () => {
this.mapShow = true // 新增代码
//...
})
},
}
}
</script>
好嘛,地图彻底渲染不出来了,然后就形成了坑三。
坑三:粗暴v-if下地图不渲染
坑三图示如下:
出现坑三的原因是下面代码的拦截:
if(!this.$refs.mapWrap) { // mapWrap获取不到时,往下走会报错
return
}
也就是说地图DOM获取不到时,是不能初始化地图的。为了保证成功初始化地图,又加了如下代码。
initMap() {
// ...
// 以下是改造的代码
if(!this.$refs.mapWrap) {
let timer = null
timer = setInterval(() => {
setTimeout(() => {
this.mapInit()
},200)
if(this.$refs.mapWrap&&timer) {
clearInterval(timer)
}
}, 300 )
} else {
setTimeout(() => {
this.mapInit()
},200)
}
}
通过定时器的方式保证,页面始终在正确的方式下渲染地图。
至于在setInterval中又加了setTimeout是因为,即使this.$refs.mapWrap有了,如果立马初始化地图,也是有可能不成功的,会出现坑三图示中的报错。
以上,就是在页面中渲染地图而踩的坑。注意是页面,如果是在弹框中渲染地图,是没有上述坑的,因为在弹框的显隐中已经有v-if控制了。