欢迎来到 WebGIS 入门系列的第十一篇文章!在本文中,我们将介绍如何利用高德地图的地理编码服务以及 axios 和 lodash 库来实现行政区划模块。通过本文的学习,您将掌握如何在 WebGIS 应用中实现行政区划的查询和展示功能。
行政区划菜单及面板实现
在 MapTools
组件中增加一个新菜单,用于实现行政区划定位功能,默认值使用“成都市”(按需设置即可):
<template>
<div class="map-tools">
<span class="map-tool-item">成都市</span>
<span class="map-tool-item" @click="handleSpaceQueryBtnClick"
>空间查询</span
>
<span class="map-tool-item">菜单-3</span>
<span class="map-tool-item">菜单-4</span>
<span class="map-tool-item">菜单-5</span>
<span class="map-tool-item" @click="handleClearScreen">清屏</span>
</div>
</template>
// ......
在 src/components
目录下新建 CityPanel
组件,并将下述代码拷贝至其中:
<template>
<div class="city-panel">
<div class="city-panel-herder">
<span>当前城市:{{ currentCity }}</span>
</div>
<div class="city-panel-content">
<div
v-for="province in provinceData"
:key="province.code"
class="province-item"
>
<span>{{ province.name }}</span>
<div class="city">
<div v-for="city in cityData" :key="city.code" class="city-item">
<span v-if="city.provinceCode === province.code"
>{{ city.name }}</span
>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue"
import provinceData from "@/data/provinces.json"
import cityData from "@/data/cities.json"
const currentCity = ref("四川省成都市")
console.log(provinceData, cityData)
</script>
<style scoped>
.city-panel {
position: absolute;
top: 60px;
right: 65px;
width: 450px;
height: 400px;
padding: 0 16px;
background-color: rgba(255, 255, 255, 0.85);
box-shadow: 1px 2px 1px rgba(0, 0, 0, 0.15);
box-sizing: border-box;
}
.city-panel-herder {
height: 48px;
display: flex;
align-items: center;
border-bottom: 1px solid #bfbfbf;
box-sizing: border-box;
}
.city-panel-herder span {
font-size: 16px;
font-weight: 600;
}
.city-panel-content {
height: calc(100% - 48px);
padding: 8px 0;
box-sizing: border-box;
overflow: auto;
}
.province-item {
display: flex;
color: #5f6477;
font-size: 12px;
font-weight: 700;
margin-bottom: 16px;
}
.province-item:last-child {
margin-bottom: 0;
}
.province-item > span {
min-width: 100px;
}
.city-item {
float: left;
color: #999999;
}
.city-item:hover {
color: #4096ff;
}
.city-item > span {
display: inline-block;
margin-right: 16px;
cursor: pointer;
}
</style>
将 CityPanel
组件引入至 MapView
组件,在浏览器可看到新建的行政区划组件界面:
行政区划跳转逻辑实现
预期实现效果:点击各个城市名称,地图中心点跳转至相应城市。
在 CityPanel
组件中的 city-item
元素内的 span
标签上绑定 click
事件,主要实现更新行政区划面板中当前城市名称、实现地图中心点跳转,代码如下:
<template>
// ......
<div v-for="city in cityData" :key="city.code" class="city-item">
<span
v-if="city.provinceCode === province.code"
@click="handleCityBtnClick(province, city)"
>{{ city.name }}</span
>
</div>
// ......
</template>
<script setup lang="ts">
// ......
import lodash from "lodash"
import axios from "axios"
import { useMapViewStore, useCityPanelStore } from "@/stores/counter"
import { openMessage } from "@/libs/utils"
import type { MapViewData } from "@/interface/index"
const mapViewStore = useMapViewStore()
const cityPanelStore = useCityPanelStore()
// ......
function handleCityBtnClick(
province: {
code: string
name: string
},
city: { code: string; name: string; provinceCode: string }
) {
const mapView = mapViewStore.mapView as MapViewData
currentCity.value = `${province.name}${city.name}`
cityPanelStore.setCityPanelCity(city.name)
axios
.get("https://restapi.amap.com/v3/geocode/geo", {
params: {
key: "你的高德地图 Web 服务 API Key",
address: `${province.name}${city.name}`,
},
})
.then((res) => {
const location = lodash
.get(res, "data.geocodes[0].location", "")
.split(",")
mapView.goTo({
center: [Number(location[0]), Number(location[1])],
zoom: 10,
})
})
.catch((err) => {
console.error(err)
openMessage("网络错误,请联系管理员", "error")
})
}
</script>
上述代码中使用到了两个库:lodash
和 axios
,前者是简化 js 代码逻辑,类似于一个 js 工具库,后者是用于发送网络请求。针对这两个库,如果有不了解的建议去各自官网学一学基础知识即可。
除此之外,为了得到各个城市的经纬度坐标值,此处使用了高德地图的地理编码接口,同理,如果有不了解高德地图 API
的也建议去官网学一学基础知识。
最后,我们点击各个城市名时,除了更新 state
之外,还更新了 store
中的数据,所以我们在 store
中也存放了两个变量信息,主要控制行政区划面板显示/隐藏以及存放当前选中的城市名称:
export const useCityPanelStore = defineStore("cityPanel", () => {
const cityPanel = ref({
visible: false,
city: "成都市",
})
function setCityPanelVisible(val: boolean) {
cityPanel.value.visible = val
}
function setCityPanelCity(val: string) {
cityPanel.value.city = val
}
return { cityPanel, setCityPanelVisible, setCityPanelCity }
})
然后回到 MapTools
组件中,在行政区划菜单上面绑定 click
事件,主要更新面板的显示/隐藏状态,以及显示当前存放在 store
中的城市名称:
<template>
<div class="map-tools">
<span class="map-tool-item" @click="handleXZQHBtnClick">{{
cityPanelStore.cityPanel.city
}}</span>
// ......
</div>
</template>
<script setup lang="ts">
import { useMapViewStore, useCityPanelStore } from '@/stores/counter'
// ......
const mapViewStore = useMapViewStore()
const cityPanelStore = useCityPanelStore()
// ......
function handleXZQHBtnClick() {
cityPanelStore.setCityPanelVisible(!cityPanelStore.cityPanel.visible)
}
同理,在 CityPanel
组件中也要根据 store
中面板的显示/隐藏状态值更新此面板的显示和隐藏:
<template>
<div class="city-panel" v-show="cityPanelStore.cityPanel.visible">
// ......
</div>
</template>
此时在界面就可以看到行政区划完整的功能了:
小作业:代码优化
虽然按照上述操作完成了行政区划模块的功能,但是有部分代码可以进行优化,例如点击各个直辖区时,菜单上面展示的是“直辖区”三个字的文案,预期是要展示直辖市名称;保存当前选中的城市时,其实不用 state
和 store
两份数据,只用 store
就可以……
结语
通过本文的学习,您已经掌握了如何利用高德地图的地理编码服务以及 axios 和 lodash 库来实现行政区划模块。行政区划查询是 WebGIS 应用中常见的功能之一,能够帮助用户快速获取感兴趣区域的行政区划信息。 希望本文能够为您在行政区划模块的实现方面提供一定的帮助,并且启发您进一步探索 WebGIS 开发的世界。祝您在 WebGIS 开发的旅程中取得成功!