你们好,我是金金金。
前言
撰写本文的初衷既是为了方便各位读者,也是为了自我提升。在未来面对一些基本操作时,我们不再需要频繁查阅官方文档,节省宝贵的时间。网络上的相关资料虽然丰富,但质量良莠不齐,查找起来颇为不便。因此,我希望通过这篇整理详尽、条理清晰的文章,为大家提供一个可靠的信息来源
看完本篇文章能学到什么?
如何把高德地图引入至Vue3项目中;
地图正常展示;
根据经纬度打点标记、自定义图标;
点标记覆盖物如何触发点击事件;
点击点标记覆盖物打开自定义信息窗体展示;
点聚合;
点聚合点击判断的一个方式;
实操
引入高德地图至Vue3项目中以及地图的一个正常展示
- 成为开发者并创建
key
(为了正常调用 API ,需先注册成为高德开放平台开发者,并申请 web 平台(JS API)的 key 和安全密钥)- 这里不过多赘述,自己去申请注册一下,点击可跳往操作地址
- 提示:在2021年12月02日以后申请的
key
需要配合安全密钥一起使用。
NPM
安装Loader
npm i @amap/amap-jsapi-loader --save
- 新建一个组件,我这里名为
MapContainer.vue
,用作地图组件(名字随意) - 创建地图容器
- 在
MapContainer.vue
地图组件中创建div
标签作为地图容器 ,并设置地图容器的id
属性为container
<template> <div id="container"></div> </template>
- 在
- 设置地图样式
<style scoped> #container { width: 100%; height: 100%; } </style>
- 初始化地图
onMounted(() => { window._AMapSecurityConfig = { securityJsCode: "「你申请的安全密钥」", }; AMapLoader.load({ key: "", // 申请好的Web端开发者Key,首次调用 load 时必填 version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15 plugins: ["AMap.Scale"], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['...','...'] }) .then((AMap) => { map = new AMap.Map("container", { // 设置地图容器id viewMode: "3D", // 是否为3D地图模式 zoom: 11, // 初始化地图级别 center: [116.397428, 39.90923], // 初始化地图中心点位置 }); }) .catch((e) => { console.log(e); }); })
好了,大概的步骤就是这么多,所有代码如下
测试
根据经纬度打点标记、自定义图标
分为三步走
- 创建
Marker
对象 - 自定义
Icon
传入至Marker
- 将
Marker
添加到地图上
添加多个点标记也很简单,传入多个经纬度数组数据,循环创建
Marker
添加即可
测试
点标记覆盖物如何触发点击事件
- 比较简单,使用
marker
对象.on
方法就可以监听到点击事件
marker.on('click', function (e) {
alert("我被点击了")
})
测试
点击点标记覆盖物打开自定义信息窗体展示
注意:一个地图实例每次只能打开一个信息窗体
- 先看一下默认信息窗体如何展示
默认信息窗体
- 默认信息窗体已有关闭按钮,只需要设定
InfoWindow
的content
属性。content
是字符串拼接的DOM
元素,content
的样式可以自定义。
很简单,也可以分三步走
- 编写信息窗体的内容
- 创建
infoWindow
实例,传入信息窗体内容 - 打开显示信息窗体
// 信息窗体的内容
const content = [
"<div><b>高德软件有限公司</b>",
"电话 : 010-84107000 邮编 : 100102",
"地址 : 北京市望京阜通东大街方恒国际中心A座16层</div>",
]
// 创建 infoWindow 实例
const infoWindow = new AMap.InfoWindow({
content: content.join("<br>"), // 传入字符串拼接的 DOM 元素
anchor: "top-left", // 指定自定义锚点位置
})
// 打开信息窗体
infoWindow.open(map, map.getCenter()); // map 为当前地图的实例,map.getCenter() 用于获取地图中心点坐标。
信息窗体通常是和点击事件配合使用的,例如:点击了某个覆盖物弹出相关信息
-
当覆盖物被点击时,调用打开信息窗体的方法
-
信息窗体代码如下
测试
自定义信息窗体
有些时候默认的信息窗体是不能满足业务需求的,比如框和关闭的
icon
都要改动,那就需要完全自定义信息窗体了
要自定义信息窗体,只需把
InfoWindow
的isCustom
属性设置为true
,信息窗体就会变成自定义信息窗体。与默认信息窗体的不同在于,自定义信息窗体需要自己通过content
来实现关闭按钮以及全部外观样式,同时需要通过offset
指定锚点位置,offset
为相对于content
下边缘中间点的位移
这里的重点其实就是
css
的编写了,因为使用了自定义信息窗体,框的样式都需要自己编写。
测试
自定义信息窗体事件触发
- 通过onclick绑定了事件
- 定义相对应的方法
- 需要挂载到window全局上,不然会报错函数未定义
测试
- 点击手环详情以及关闭自定义信息窗体都是没有任何问题的
点聚合
有两种方式,分别为:按距离聚合和按索引聚合。我这里采用的是按距离聚合
大致步骤可以分为三步走
- 创建聚合点数据
- 自定义图标样式
- 添加聚合组件
// 点聚合数据
const _renderMarker = (context) => {
// context 为回调参数,
// 包含如下属性 marker:当前非聚合点
context.marker.setContent(`<img src="${CourtDIcon}" alt="" />`)
}
const points = [
{ weight: 8, lnglat: ['120.475655', '27.570581'] },
{ weight: 1, lnglat: ['120.472792', '27.564668'] },
{ weight: 1, lnglat: ['120.551636', '27.66167'] },
{ weight: 1, lnglat: ['120.546932', '27.773796'] },
{ weight: 1, lnglat: ['120.341914', '27.644967'] },
]
// 点聚合
new AMap.MarkerCluster(map, points, {
gridSize: 60, //数据聚合计算时网格的像素大小
renderMarker: _renderMarker, //上述步骤的自定义非聚合点样式
})
点聚合点击判断
其实也很简单,思路:通过包含点的数量判断是否是聚合点,数量为1说明不是聚合点
一些参考的代码我贴出来供大家参考~
全部代码
<script setup>
import { onMounted, onUnmounted, ref } from 'vue'
import AMapLoader from '@amap/amap-jsapi-loader'
import WristbandIcon from '@/assets/imgs/device/ding_wei.png'
import UserIcon from '@/assets/imgs/user.png'
import ServiceIcon from '@/assets/imgs/service.png'
import CourtDIcon from '@/assets/imgs/court_d.png'
let map = null
const infoWindow = ref(null)
const closeInfo = () => {
infoWindow.value?.close()
}
const handleWristbandClick = () => {
alert("点击了手环")
}
const _renderMarker = (context) => {
// context 为回调参数,
// 包含如下属性 marker:当前非聚合点
context.marker.setContent(`<img src="${CourtDIcon}" alt="" />`)
}
const openInfo = () => {
// 构建信息窗体中显示的内容
const info = []
info.push('<div class="info-box">')
// 主题内容部分
info.push('<div class="info-box-main">')
info.push(`<img class="info-box-main-img" src="${UserIcon}" alt="" />`)
info.push('<div>')
info.push(`<p>姓名: 张三</p>`)
info.push(`<p>电话: 18888888888</p>`)
info.push('</div>')
info.push('</div>')
// 手环
info.push('<div class="info-box-footer">')
info.push(`<img class="info-box-footer-img" src="${ServiceIcon}" alt="" />`)
info.push('<span οnclick="handleWristbandClick()">手环详情</span>')
info.push('<span>></span>')
info.push('</div>')
info.push('</div>')
// 三角
info.push('<div class="info-triangle">')
info.push('</div>')
// 关闭按钮
info.push('<div class="info-close" οnclick="closeInfo()">×')
info.push('</div>')
// 创建 infoWindow 实例
infoWindow.value = new AMap.InfoWindow({
isCustom: true, //使用自定义窗体
content: info.join('<br>'), //传入字符串拼接的 DOM 元素
anchor: 'top-left', // 指定自定义锚点位置
})
// 打开信息窗体
infoWindow.value.open(map, map.getCenter()) //map 为当前地图的实例,map.getCenter() 用于获取地图中心点坐标。
}
onMounted(() => {
window._AMapSecurityConfig = {
securityJsCode: '这里填写你的密钥',
}
AMapLoader.load({
key: '这里写你申请的key', // 申请好的Web端开发者Key,首次调用 load 时必填
version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: ['AMap.Scale'], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['...','...']
})
.then((AMap) => {
map = new AMap.Map('container', {
// 设置地图容器id
viewMode: '3D', // 是否为3D地图模式
zoom: 11, // 初始化地图级别
center: [116.397428, 39.90923], // 初始化地图中心点位置
})
// 创建一个 icon
const wristbandIcon = new AMap.Icon({
image: WristbandIcon,
})
// 创建一个 marker
const marker = new AMap.Marker({
position: new AMap.LngLat(116.397428, 39.90923), // 根据经纬度设置 maker 位置
icon: wristbandIcon, // 设置图标
offset: new AMap.Pixel(-13, -30) // 设置图标偏移量
})
// 覆盖物点击事件
marker.on('click', function (e) {
openInfo()
})
// 将 marker 添加到地图
map.add([marker])
// 点聚合数据
const points = [
{ weight: 8, lnglat: ['120.475655', '27.570581'] },
{ weight: 1, lnglat: ['120.472792', '27.564668'] },
{ weight: 1, lnglat: ['120.551636', '27.66167'] },
{ weight: 1, lnglat: ['120.546932', '27.773796'] },
{ weight: 1, lnglat: ['120.341914', '27.644967'] },
]
// 点聚合
new AMap.MarkerCluster(map, points, {
gridSize: 60, //数据聚合计算时网格的像素大小
renderMarker: _renderMarker, //上述步骤的自定义非聚合点样式
})
window.closeInfo = closeInfo
window.handleWristbandClick = handleWristbandClick
})
.catch((e) => {
console.log(e)
})
})
onUnmounted(() => {
map?.destroy()
})
</script>
<template>
<div id="container"></div>
</template>
<style lang="scss">
#container {
width: 100%;
height: 100%;
}
.info-box {
padding: vw(15);
color: #fff;
background-color: #01161ccc;
box-shadow: inset vw(-2) 0 vw(8) vw(2) #428ffccc, 0 0 vw(6) vw(2) #00000088;
border: vw(2) solid rgb(86, 156, 255);
border-radius: vw(10);
&-main {
display: flex;
align-items: center;
font-size: vh(16);
&-img {
width: vw(40);
height: vw(40);
margin-right: vw(10);
}
}
&-footer {
margin-top: vh(10);
font-size: vh(14);
color: #00e5ff;
display: flex;
align-items: center;
&-img {
width: vw(14);
height: vw(14);
margin-right: vw(3);
}
}
}
.info-triangle {
width: 0;
height: 0;
border-left: vw(8) solid transparent;
border-right: vw(8) solid transparent;
border-top: vw(8) solid #008fd4;
margin: 0 auto;
}
.info-close {
position: absolute;
right: vw(-8);
top: vw(-8);
width: vw(20);
height: vw(20);
background-color: #0ec1d4;
color: #fff;
border-radius: 50%;
font-weight: bold;
display: flex;
justify-content: center;
align-items: center;
}
</style>
- 编写有误还请大佬指正,万分感谢。