我的框架 vite + react ,其实vue也一样差不多
一.前置工作
先去官网去申请个key,地址:高德开放平台 | 高德地图API
先登录然后进入控制台
然后打开应用管理,我的应用
然后创建新应用
新建完成后,创建key
然后
提交完成,就可以拿到key了,如果一开始需要认证就认证一下
二.安装amap
可以npm 或者 yarn 安装
npm install @amap/amap-jsapi-loader
然后正式开始编写代码咯
三.引入amap组件和使用(react版本)
import AMapLoader from "@amap/amap-jsapi-loader";
import { useEffect, useLayoutEffect, useRef, useState } from "react";
import { createRoot } from "react-dom/client";
import { renderToString } from "react-dom/server";
//设置在外面,方便调用
let amap;
let infoWindow;
//测试数据
//数据
let markersDate = [
{
id: 1,
text: "测试1",
position: [108.971179, 34.29238],
},
{
id: 2,
text: "测试2",
position: [108.976082, 34.295203],
]
//自定义样式
function cameraCard() {
//创建一个div
const container = document.createElement("div");
//编写html代码,样式自己写class,vue也是同理
const vnode = (
<div className="imgBox">
<img className="mapicon" src={} alt="" />
</div>
);
const root = createRoot(container);
//创建注册节点
root.render(vnode);
return container;
}
//自定义窗体,没有啥交互可以这样写,如果有交互,还得使用render注册
function mapCard() {
const sort = <div className="mapCardBox"></div>;
const vnode = (
<div
id="mapCardBox"
className="amap-label dashboard-borderbox-wrap amapLocation"
>
我是窗体1
</div>
);
//转成字符串
return renderToString(vnode);
}
//点击后的自定义窗口
function VideoCard(){
const container = document.createElement("div");
const vnode = (
<div className="videoBox">
我是窗体222
</div>
);
const root = createRoot(container);
root.render(vnode);
return container;
}
//窗口关闭方法,目前还没调用
//关闭
function closeInfoWindow(){
infoWindow.close();
};
//主函数
function Map() {
//地图样式,如果没有可以删除
const G4 = {
default: "amap://styles/*****************",
dark: "amap://styles/*****************",
};
const mapStyle = G4.default
const initMap = () => {
AMapLoader.load({
key: "********************", // 申请好的Web端开发者Key,首次调用 load 时必填
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: [
"AMap.MouseTool",
"AMap.Geolocation",
"AMap.Geocoder",
"AMap.MarkerClusterer",
"AMap.PlaceSearch",
"AMap.Weather",
"AMap.GeometryUtil",
"AMap.Weather",
], //插件列表
})
.then((AMap) => {
//下面这个mapContainer是id
amap = new AMap.Map("mapContainer", {
mapStyle: mapStyle,//设置自己的地图模式,如果没有可以删除
resizeEnable: true,
rotateEnable: false,
pitchEnable: true,
zoom: 16,//进入页面的默认值值
pitch: 50,//倾斜角度
rotation: 0,
viewMode: "3D",//切换2D模式
expandZoomRange: true,
zooms: [6, 20],//设置视图最小值和最大值
center: [108.946651, 34.222718], //初始化地图中心点位置
showLabel: true,
});
//遍历添加标注点位,如果只有一个,不用遍历即可
markersDate.forEach(function (item) {
let marker = new AMap.Marker({
position: item.position,//坐标
ofzzfset: new AMap.Pixel(0, 0),//点位偏移度
visible: true,
content: mapIcon(),//自定义点位样式,写jsx格式,方法在上面
label: {
content: mapCard(),//自定义窗体,不需要可以删除该行,这里有个坑,需要是string的,所以需要用renderToString 来转
direction: "left",//窗体位置
offset: new AMap.Pixel(0, 30),//偏移位置
},
});
//添加点击方法,item是数组数据
marker.on("click", (evt) => showInfoM(item, evt));
//添加点位
amap.add(marker);
})
//点击事件
function showInfoM(item, evt) {
//打开弹窗窗口
openInfoWindow(evt.target._position, item);
}
//打开窗口
function openInfoWindow(pos, item) {
infoWindow = new AMap.InfoWindow({
content: VideoCard(), // 使用默认信息窗体框样式,显示信息内容,jsx格式
offset: new AMap.Pixel(40, 40),//偏移位置
anchor: "none",
isCustom: true,
// closeWhenClickMap: true, //点外部地图关闭
retainWhenClose: true,
});
//打开窗口,pos == evt.target._position,是传进来的参数
infoWindow.open(amap, pos);
}
//自动会集中在各个点位的中心点
//根据地图上添加的标记或覆盖物的位置,自动调整地图的缩放级别和中心点
amap.setFitView();
//amap.remove(markerList[e]);
})
.catch((e) => {
console.log(e);
});
};
//初始化地图,react钩子函数,类似vue的生命周期
useEffect(() => {
//地图的方法
initMap();
}, []);
return (
<div id="mapContainer" style={
{ width:'100vw',height:'100vh';}}></div>
);
}
export default Map;
三.删除点位和新增点位
如果需要隐藏或者删除点位的话,使用 amap.remove(需要删除的数组)
amap.remove([]);//[]是需要删除的数组,这也是为什么我需要把amap定义在函数外面的原因,因为删除更新我都需要用到amap
[]是需要删除的数组,这也是为什么我需要把amap定义在函数外面的原因,因为删除更新我都需要用到amap
如果存在多个数组点位增删改查的的话也很好解决
同理
let list1= [
{
id:1,
name:"hh"
}
]
//定义个数组
let arr = []
//存进来这个,可以用来清空指定的数组
let markerList = [[][]]
//这个onfun是一个点击事件,作用于就是点那个按钮就显示那个数组里面的内容一样,e是个number,data是外部传入的一个数组,如<div onclick={()=>{onfun(0,list1)}}>点击</div> 这样
const onfun = (e,data)=>{
arr[e] = data
//这个是新增,这块最好也加个判断条件,是新增还是删除
if(判断条件){
//新增
arr[e].forEach(function (item: any) {
let marker = new AMap.Marker({
position: item.position,
ofzzfset: new AMap.Pixel(0, 0),
visible: true,
content: mapIcon(item),
label: {
content: mapCard(),
direction: "left",
// offset: new AMap.Pixel(0, 30),
},
// content:marker.content
});
//存入数组之中
markerList[e].push(marker);
//绑定点击事件
marker.on("click", (evt: any) => console.log("点击了"));
amap.add(marker);
});
}else{
//这个是删除,清空指定的数组
amap.remove(markerList[e]);
//关闭窗口
infoWindow.close();
//初始化数组
markerList[e] = [];
}
}
四.react数组更新注意事项
如果是react的话需要用到useState()钩子函数,然后就是useState()使用中需要注意的东西,比如
//这里定义是一个数组,如果需要更新一个数组的话,必须需要把数组解出来
let [getArr, setArr] = useState([]);
//这边定义一个数组
let arr = [1,2,3]
//正确更新方式
setArr(...arr)
//错误方式setArr(arr)
五.amap地图样式更新
关于地图的样式的切换,使用amap.setMapStyle(样式)这样切换就不需要重新调用地图方法了,而且重新调用地图虽然也能切换地图但是会闪一下,及其不友好
//使用amap.setMapStyle()
const G4 = {
default: "amap://styles/*****************",
dark: "amap://styles/*****************",
};
let mapStyle = G4.default;
//这样切换就不需要重新调用地图方法了,而且重新调用地图虽然也能切换地图但是会闪一下,及其不友好
amap.setMapStyle(mapStyle);
六.地图自定义图标窗口偏移问题
坑!:然后还有刷新出现地图点位偏移的一个问题,以及在地图外点击显示点位,出现布局错乱或者是偏移的问题
这个时候只需要去浏览器f12 巡查一下代码,找到amap的css样式,给样式加上个绝对定位即可解决问题,如果在当前节点不生效进行往上一个节点写绝对定位,如我这个,这个应该是必加的,去除边框自定义边框,去除内边距,然后通过left和top调整,这样的话即使在地图外显示点击新增点位,也不会给display:none影响到,样式丢失也是display:none导致的。因为地图你的点位不在你屏幕的可视范围内的话,那些点位元素是属于一个display:none的一个状态,display:none的是不占用空间的,当display:none在demo节点上面是直接删除的,所以会导致一个样式丢失的一个问题
so,以下代码最好还是加上,就把问题解决了,当然可能也有更好其他方法
.amap-marker-label {
padding: 0;
border: none;
background-color: unset;
position: absolute;
left: -150px !important;
top: -15px !important;
}
还有一个是图标偏移问题,这个就很好解决了,
如代码
//这个是一个自定义的图标,amap地图,点位的自定义图片
function cameraCard(src = iconA) {
const vnode = (
<div className="imgBox">
<img className="mapicon" src={src} alt="" />
</div>
);
return vnode;
}
如果刷新,或者数据变动的话的这个图标就会出现一个偏移
所以直接给imgBox这个css加上绝对定位即可解决
.imgBox {
position: absolute;
}
七.地图transform和position: fixed冲突问题
然后就是在地图内部,不建议使用position: fixed;因为amap使用了大量的transform,而transform是和position: fixed冲突的,会把position: fixed 降级为absolute,达不到窗口定位的一个效果!所以还是把需要用到position: fixed 用的html 放在地图外边
以上代码皆为手敲,如有错误,望能指出