接入之前的准备工作:
- 需要有一个账号,网址:https://developer.amap.com/product/map#/
- 然后必须先申请自己的key和安全密钥,网址: https://lbs.amap.com/api/javascript-api/guide/abc/prepare
可以在自己的项目中接入了:
-
先安装依赖:
npm
方式:npm i @amap/amap-jsapi-loader --save
yarn
方式:yarn add @amap/amap-jsapi-loader --save
-
引入下载的依赖包:
import AMapLoader from '@amap/amap-jsapi-loader'
-
在页面中想放地图的地方加
<div id="替换自己的id"></div>
,并加上CSS
宽高,不加页面会看不到 -
onMounted
中初始化地图:这时在页面就可以看到简单地图了window._AMapSecurityConfig = { securityJsCode: '替换自己的安全密钥', // 安全密钥 } // AMapLoader => 加载器 资源加载完成后就会触发 then AMapLoader.load({ key: '替换自己的key', // 申请好的Web端开发者Key,首次调用 load 时必填 version: '2.0', // 指定要加载的 JS API 的版本,缺省时默认为 1.4.15 plugins: [ // 需要使用的的插件列表,如比例尺'AMap.Scale'等 'AMap.ToolBar', // 缩放工具条 'AMap.Scale', // 比例尺 'AMap.Geolocation', //定位,提供了获取用户当前准确位置、所在城市的方法 'AMap.Geocoder', // 坐标 -> 地址 'AMap.ElasticMarker', // 灵活点标记 'AMap.AutoComplete', // 输入提示 'AMap.PlaceSearch', // 搜索 'AMap.DistrictSearch', // 行政区查询服务 'AMap.CitySearch', // 城市获取服务,获取用户所在城市 ], }) .then((AMap) => { //设置地图容器id state.map = new AMap.Map('替换自己div的id', { zoom: 10, //初始化地图层级 viewMode: '3D', //是否为3D地图模式 scrollWheel: true, //鼠标滚轮放大缩小 doubleClickZoom: true, //双击放大缩小 keyboardEnable: true, //键盘控制放大缩小移动旋转 }) // 初始化插件 // loadPlugin() // 可写其他逻辑 }) .catch(() => { Toast('地图加载失败') })
-
后面就可以利用高德提供的插件来定制化了,在初始化地图成功的回调里初始化插件,插件网址:https://lbs.amap.com/api/javascript-api-v2/guide/abc/plugins-list
const loadPlugin = () => { /* 工具条插件 */ AMap.plugin(['AMap.ToolBar', 'AMap.Scale'], function () { //在回调函数中实例化插件,并使用插件功能 const toolbar = new AMap.ToolBar() //创建工具条插件实例 state.map.addControl(toolbar) //添加工具条插件到页面 const scale = new AMap.Scale() state.map.addControl(scale) }) /* 搜索 */ AMap.plugin('AMap.PlaceSearch', function () { state.placeSearch = new AMap.PlaceSearch({ map: state.map, autoFitView: false, showCover: true, pageIndex: state.pageIndex, }) }) /* 行政区搜索 */ AMap.plugin('AMap.DistrictSearch', function () { if (!state.district) { state.district = new AMap.DistrictSearch({ subdistrict: 3, //获取边界不需要返回下级行政区 extensions: 'all', //返回行政区边界坐标组等具体信息 level: 'district', //查询行政级别为 市 }) } state.district.setLevel('district') }) /* 定位 */ AMap.plugin('AMap.Geolocation', function () { state.geolocation = new AMap.Geolocation({ enableHighAccuracy: true, // 是否使用高精度定位,默认:true timeout: 10000, // 设置定位超时时间,默认:无穷大 offset: [10, 20], // 定位按钮的停靠位置的偏移量 zoomToAccuracy: true, // 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false position: 'RB', // 定位按钮的排放位置, RB表示右下 }) }) /* 初始化marker */ state.marker = new AMap.Marker() /* 使用到了根据经纬度获取地址 */ AMap.plugin('AMap.Geocoder', function () { state.geocoder = new AMap.Geocoder() }) }
-
在插件初始化完之后可以使用插件的方法进行定制化,整理用到的插件网址
-
插件的使用文档:https://lbs.amap.com/api/javascript-api-v2/guide/abc/plugins
-
AMap.PlaceSearch
的详细方法和传参网址:https://lbs.amap.com/api/javascript-api/reference/search#m_AMap.PlaceSearch -
AMap.DistrictSearch
的详细方法和传参网址:https://lbs.amap.com/api/javascript-api/reference/search#m_AMap.DistrictSearch -
AMap.Geolocation
的详细方法和传参网址:https://lbs.amap.com/api/javascript-api/reference/location#m_AMap.Geolocation -
AMap.Geocoder
的详细方法和传参网址:https://lbs.amap.com/api/javascript-api/reference/lnglat-to-address#m_AMap.Geocoder
-
全部代码如下:
<template>
<div id="map"></div>
<div>
<div class="flex aic" style="background: #fff">
<van-search
id="search"
v-model.trim="state.keyword"
class="flex1"
placeholder="请输入地址关键词"
shape="round"
show-action
>
<template #action>
<div @click="onSearch">搜索</div>
</template>
</van-search>
<div style="padding: 0 14px 0 4px; font-size: 14px" @click="sureClose">
确定
</div>
</div>
<div class="list">
<van-list
v-if="!state.empty"
v-model:error="state.error"
v-model:loading="state.loading"
error-text="请求失败,点击重新加载"
:finished="state.finished"
finished-text="没有更多了"
:immediate-check="false"
@load="nextPageSearch"
>
<template v-for="s in state.searchList" :key="s.id">
<van-cell
center
:label="itemLabel(s)"
style="--van-cell-line-height: 20px"
:title="`${
s.address === s.adname && s.adname !== s.name
? itemLabel(s)
: s.name
}`"
@click="searchItemClick(s)"
>
<template #value>
<img
fit="contain"
height="14"
:src="
state.checkedId == s.id
? require('@/assets/images/mine/checked.png')
: require('@/assets/images/mine/noCheck.png')
"
width="14"
/>
</template>
</van-cell>
</template>
</van-list>
<van-empty
v-if="state.empty"
description="暂无数据"
:image="require('@/assets/images/noData.png')"
:image-size="[150, 126]"
/>
</div>
</div>
</template>
<script setup>
import AMapLoader from '@amap/amap-jsapi-loader'
import { Toast } from 'vant'
const route = useRoute()
const router = useRouter()
const state = reactive({
areaList: computed(() => getters['common/city']),
loading: false,
finished: false,
error: false,
empty: false,
keyword: '', // 搜索值
map: undefined,
autocomplete: undefined,
placeSearch: undefined,
district: undefined,
polygon: undefined,
geolocation: undefined,
marker: undefined,
geocoder: undefined,
pageIndex: 1,
searchList: [],
checkedId: '',
selectItem: {},
})
const areaList = computed(() => {
return JSON.parse(window.sessionStorage.getItem('city'))
})
const itemLabel = (s) => { // 搜索的数据名字会有重复的需要注意处理
return `${s.pname === s.cityname ? s.pname : `${s.pname} ${s.cityname}`} ${
s.name === s.adname ? '' : s.adname
} ${s.address === s.adname ? '' : s.address}`
}
const sureClose = () => {
// 数据可能和自己库的不一致,需要自己修改,我这里是修改了citycode
const adcode = ['710000', '810000', '820000'].includes(
state.selectItem.pcode
)
? state.selectItem.pcode
: state.selectItem.adcode
const city = areaList.value.filter((f) => f.id == adcode)[0]
window.sessionStorage.setItem(
'gdAddress',
JSON.stringify({
...state.selectItem,
areaName: city.fullName,
citycode: city.parentId,
})
)
router.go(-1)
}
const onSearch = () => {
if (!state.keyword) {
return
} else {
clearPolygon()
state.map.remove([state.marker])
state.pageIndex = 1
state.searchList = []
nextPageSearch()
}
}
const searchItemClick = (s) => {
state.selectItem = s
state.checkedId = s.id
const city = areaList.value.filter(
(f) => f.name == s.name || f.fullName == s.name
)
if (
city.length !== 0 &&
['省', '市', '区', '县'].includes(
s.name.substring(s.name.length - 1, s.name.length)
)
) { // 进行行政区搜索
districtSearch(s.adcode)
} else {
clearPolygon()
state.map.setZoomAndCenter(12, [s.location.lng, s.location.lat])
state.map.remove([state.marker])
state.marker = new AMap.Marker({
label: { content: s.name, direction: 'top' }, // 文本标注
position: new AMap.LngLat(s.location.lng, s.location.lat),
})
state.map.add([state.marker])
}
}
const loadPlugin = () => {
/* 工具条插件 */
AMap.plugin(['AMap.ToolBar', 'AMap.Scale'], function () {
//在回调函数中实例化插件,并使用插件功能
const toolbar = new AMap.ToolBar() //创建工具条插件实例
state.map.addControl(toolbar) //添加工具条插件到页面
const scale = new AMap.Scale()
state.map.addControl(scale)
})
/* 搜索 */
AMap.plugin('AMap.PlaceSearch', function () {
state.placeSearch = new AMap.PlaceSearch({
map: state.map, // 会在地图标注
autoFitView: false, // 地图是否显示能看到搜索结果的所有标注
showCover: true,
pageIndex: state.pageIndex,
})
})
/* 行政区搜索 */
AMap.plugin('AMap.DistrictSearch', function () {
if (!state.district) {
state.district = new AMap.DistrictSearch({
subdistrict: 3, //获取边界不需要返回下级行政区
extensions: 'all', //返回行政区边界坐标组等具体信息
level: 'district', //查询行政级别为 市
})
}
state.district.setLevel('district')
})
/* 浏览器定位 */
AMap.plugin('AMap.Geolocation', function () {
state.geolocation = new AMap.Geolocation({
enableHighAccuracy: true, // 是否使用高精度定位,默认:true
timeout: 10000, // 设置定位超时时间,默认:无穷大
offset: [10, 20], // 定位按钮的停靠位置的偏移量
zoomToAccuracy: true, // 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
position: 'RB', // 定位按钮的排放位置, RB表示右下
})
})
/* 初始化marker */
state.marker = new AMap.Marker()
/* 使用到根据经纬度获取地址 */
AMap.plugin('AMap.Geocoder', function () {
state.geocoder = new AMap.Geocoder()
})
}
// 清除行政区polygon
const clearPolygon = () => {
if (state.polygon) {
state.map.remove(state.polygon)
state.polygon = null
}
}
// 添加marker
const addNewMarker = (lng, lat) => {
state.map.remove([state.marker]) // 删除标记
state.marker = new AMap.Marker({
position: new AMap.LngLat(lng, lat),
})
state.map.add([state.marker]) // 添加标记
state.marker.setPosition([lng, lat])
lnglatAddress(lng, lat, () => {
searchKerword()
}) // 根据经纬度获取地址给marker添加label
}
const nextPageSearch = () => { // 滑到底部请求下一页
AMap.plugin('AMap.PlaceSearch', function () {
state.placeSearch = new AMap.PlaceSearch({
map: state.map,
autoFitView: false,
pageIndex: state.pageIndex,
})
})
searchKerword()
}
// 根据输入内容搜索
const searchKerword = () => {
state.placeSearch.search(state.keyword, (status, result) => {
if (status == 'complete') {
state.loading = false
state.searchList =
state.pageIndex === 1
? result.poiList.pois
: [...state.searchList, ...result.poiList.pois]
state.checkedId =
state.searchList.length !== 0 && state.pageIndex === 1
? result.poiList.pois[0].id
: state.checkedId
if (result.poiList.count && state.searchList.length !== 0) {
state.empty = false
state.pageIndex === 1 && searchItemClick(result.poiList.pois[0])
state.finished = result.poiList.pois.length < 10
state.pageIndex += 1
} else {
state.empty = true
}
} else {
state.finished = true
state.loading = false
}
})
}
// 根据经纬度获取地址并建立带有label的maeker
const lnglatAddress = (lng, lat, fn) => {
state.geocoder.getAddress([lng, lat], (status, result) => {
if (status === 'complete' && result.regeocode) {
state.keyword = result.regeocode.formattedAddress
} else {
state.keyword = ''
Toast('获取地址失败')
}
state.map.setZoomAndCenter(12, [lng, lat]) // 地图显示到标记地点
// 添加地址标注
state.map.remove([state.marker])
state.marker = new AMap.Marker({
label: { content: state.keyword, direction: 'top' }, // 文本标注
position: new AMap.LngLat(lng, lat),
})
state.map.add([state.marker])
fn && fn(result.regeocode)
})
}
// 获取定位
const getLocation = () => {
state.geolocation.getCurrentPosition((status, result) => {
if (status == 'complete') {
addNewMarker(result.position.lng, result.position.lat)
} else {
Toast('获取定位失败')
}
})
}
// 行政区搜索
const districtSearch = (code) => {
state.map.remove([state.marker])
state.district.search(code, function (status, result) {
clearPolygon()
const bounds = result.districtList[0].boundaries
if (bounds) {
// 生成行政区画polygon
for (var i = 0; i < bounds.length; i += 1) {
//构造MultiPolygon的path
bounds[i] = [bounds[i]]
}
state.polygon = new AMap.Polygon({
strokeWeight: 1,
path: bounds,
fillOpacity: 0.4,
fillColor: '#80d8ff',
strokeColor: '#0091ea',
})
state.polygon.on('click', () => {
clearPolygon()
})
state.map.add(state.polygon)
state.map.setFitView(state.polygon) //视口自适应
}
})
}
// 初始化地图
const initMap = () => {
window._AMapSecurityConfig = {
securityJsCode: '替换自己的安全密钥', // 安全密钥
}
// AMapLoader => 加载器 资源加载完成后就会触发 then
AMapLoader.load({
key: '替换自己的key', // 申请好的Web端开发者Key,首次调用 load 时必填
version: '2.0', // 指定要加载的 JS API 的版本,缺省时默认为 1.4.15
plugins: [
// 需要使用的的插件列表,如比例尺'AMap.Scale'等
'AMap.ToolBar', // 缩放工具条
'AMap.Scale', // 比例尺
'AMap.Geolocation', //定位,提供了获取用户当前准确位置、所在城市的方法
'AMap.Geocoder', // 坐标 -> 地址
'AMap.ElasticMarker', // 灵活点标记
'AMap.AutoComplete', // 输入提示
'AMap.PlaceSearch', // 搜索
'AMap.DistrictSearch', // 行政区查询服务
'AMap.CitySearch', // 城市获取服务,获取用户所在城市
],
})
.then((AMap) => {
//设置地图容器id
state.map = new AMap.Map('替换自己要显示地图元素的id', {
zoom: 10, //初始化地图层级
viewMode: '3D', //是否为3D地图模式
scrollWheel: true, //鼠标滚轮放大缩小
doubleClickZoom: true, //双击放大缩小
keyboardEnable: true, //键盘控制放大缩小移动旋转
})
state.map.setDefaultCursor('pointer') // 地图小手
// 初始化插件
loadPlugin()
/* 初始化时有keyword就进行行政区搜索根据keyword搜索,没有就获取定位并进行周边搜索 */
if (state.keyword) {
searchKerword()
} else {
getLocation()
}
})
.catch(() => {
Toast('地图加载失败')
})
}
onMounted(() => {
state.keyword = route.query.keyword
initMap()
})
</script>
<style lang="scss" scoped>
#map {
width: 100%;
height: 60vh;
background: #fff;
transition: all 0.3s ease-in-out;
}
.list {
height: calc(40vh - 56px);
overflow: scroll;
:deep(.van-cell--center) {
justify-content: space-between;
.van-cell__value {
flex: none;
margin-left: 4px;
}
}
}
</style>
图示如下: