使用背景

在很多实际项目中都需要用到地图,不管是腾讯地图还是高德地图或是其他的地图,其实都是大差不差的。别人已经帮我们封装完毕,直接调用 api 即可。这次公司需要在添加或编辑的时候,能在地图中显示设备的位置,并可以搜索地址后获取经纬度。具体如图所示。

演示

实现步骤

由于我们使用的是 vue3,所以我们应该将这个地图做成一个组件,以便于复用。之前公司已经有一个最基础的地图组件,所以我们需要在最基础的显示组件上加上这些业务逻辑

编写页面结构

1
2
3
<div>
<div :id="mapId" class="mapDiv"></div>
</div>

这是原本最基础的页面样式,我们需要加上搜索框,以及经纬度搜索框。其实实现还是比较容易的,因为这些控件实际上是浮在地图之上的,所以我们让地图的父元素定位开启,接着我们写入基本结构,大概是这样。

1
2
3
4
5
<div>
<div :id="mapId" class="mapDiv"></div>
<!-- 搜索的容器 -->
<div class="search-wapper"></div>
</div>

我们给这个容器加上 position:absolute,接着就是正常写结构即可。因为我们这个控件可能是有些地方需要,有些地方不需要。所以我们在组件上写 props。

由于搜索地址的输入框与经纬度的输入不会同时出现,所以我再设一个变量用于切换两个输入框。

逻辑实现

我们通过上面编写 html 和一些基本的 vue 代码已经实现了页面的显示。现在我们需要实现模糊搜索的功能。

实际上我们是使用到了高德 api 中的 autoComplete.search 方法,该方法会根据模糊输入的查询到相对的地址。

1
2
3
4
5
6
7
8
9
10
11
12
this.debouncedChangeAddress = _.debounce((value) => {
this.searchAddressLoading = true;
autoComplete.search(value, (status, result) => {
if (status === "complete" && !_.isEmpty(result.tips)) {
this.options = result.tips;
} else {
this.options = [];
ElMessage.warning("暂无搜索地址");
}
this.searchAddressLoading = false;
});
}, 1000);

这里使用 lodash 的 debounce 做防抖操作,然后我们将这个方法绑定到 elementUi 中的下拉框中的:remote-method=”debouncedChangeAddress”。这样我们就实现了查询功能,但是查询只是返回了 address 并不是经纬度,所以我们需要使用高德的地址查询 api 也就是 getLocation。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
getCoordinates(address) {
this.map_loading = true;
this.geocode.getLocation(address, (status, result) => {
if (status === 'complete' && result.geocodes.length) {
let lnglat = result.geocodes[0].location;
const { lat, lng } = lnglat;
this.latitude = lat;
this.longitude = lng;
this.addSearchMarker(lng, lat);
} else {
console.log('根据地址查询位置失败');
}
this.$emit('mapClickInfo', {
detailedAddress: address,
siteLng: this.longitude,
siteLat: this.latitude
});
this.map_loading = false;
});
},

这里我封装成一个方法,当我们点击 select 的相的时候调用这个方法,将传入的 address 转化为经纬度。

到这里其实已经完成了从输入模糊查询到变为经纬度,接下来我们还需要根据经纬度查询具体位置,其实就是调用 getAddress 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
getLocation(siteLng, siteLat) {
this.map_loading = true;
this.geocode.getAddress([siteLng, siteLat], (status, result) => {
let detailedAddress = '';

if (status === 'complete' && result.regeocode) {
detailedAddress = result.regeocode.formattedAddress;
} else {
ElMessage.error(
i18n.global.t('page.dialog.actionFb.lngandlatQueryFailed')
);
}
this.$emit('mapClickInfo', {
detailedAddress,
siteLng,
siteLat
});
this.map_loading = false;
});
},

这样就能通过经纬度反过来查询到地址。到此我们基本完成了这个功能

总结

其实这个逻辑并不困难,但是需要懂得如何查api文档。