高德地图动态Marker和自定义弹框、交互事件、中心点跳转

发布时间 2023-06-27 19:36:12作者: 一条瓜

高德地图

vue3 使用

下载 NPM:
npm i @amap/amap-jsapi-loader --save

根据官网提示,VUE3 需要改变监听模式

下载

npm i @vue/reactivity
组件内配置初始化
<script setup>
//开发技术   vue3 pinia  ts
import { ref } from "vue";
import AMapLoader from "@amap/amap-jsapi-loader";  //引入地图
import { onMounted } from "vue";
import { shallowRef } from "@vue/reactivity";  //改变监听
let map = shallowRef(null); //设置地图

const initMap = () => {
  AMapLoader.load({
    key: "密钥", // 申请好的Web端开发者Key,首次调用 load 时必填
    version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
    plugins: [""], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
  })						//container容器
    .then((AMap) => {
      map = new AMap.Map("container", {
        //设置地图容器id  container
        viewMode: "3D", //是否为3D地图模式
        zoom: 13,//初始化地图级别
        center: [113.83804, 22.62621], //初始化地图中心点位置
        //mapStyle: "amap://styles/darkblue",  //设置样式
      });
    })
    .catch((e) => {
      console.log(e); //错误打印
    });
};

onMounted(() => {
  initMap();    //调用这个高德地图
});
</script>

<template>
  <div id="container"></div>  //容器
</template>

<style lang="scss" scoped>
#container {   //地图显示设置盒子大小
  width: 100%;
  height: 100%;
}
</style>

Marker 点创建
//抽离创建Marker点
<script>
const initMap = () => {
  AMapLoader.load({
    key: "密钥",
    version: "2.0",
    plugins: [""],
  })
    .then((AMap) => {
      map = new AMap.Map("container", {
        viewMode: "3D",
        zoom: 13,
        center: [113.83804, 22.62621],
      });
      createMarker();//创建Marker点抽离=====================================
    })
    .catch((e) => {
      console.log(e);
    });
};

onMounted(() => {
  initMap();
});
</script>

<script>  //Marker方法抽离
 let markers = ref([  //点位信息后端获取
  {
    carNum: "桂LMM267",
    in: "alert0", //样式
    position: [113.821215, 22.607418],
    zt: "离线",
  },
  {
    carNum: "粤LMM267",
    in: "alert1",
    position: [116.368904, 45.913423],
    zt: "运动",
  },
]);


const createMarker = () => {
  map.clearMap(); // 清除地图覆盖物
  markers.value.forEach(function (marker: any) { //循环创建marker点
    let markerss = new AMap.Marker({
      resizeEnable: true,
      map: map,
      content: `<div class="${marker.in}" style='color: red;'></div>`,
        //content是marker点内容  ${marker.in}动态样式
      position: [marker.position[0], marker.position[1]], //@ts-ignore
        //position配置每个marker点的位置
      offset: new AMap.Pixel(-13, -30),
        //offset配置marker点偏移量
    });

      markerss.setLabel({
      direction: "centre",
      offset: new AMap.Pixel(0, 50), //设置文本标注偏移量
      content: `<div class='info'>${marker.carNum}</div>`, //设置文本标注内容
    });
      //setLabel是marker点底部的提示标签

    markerss.orderno = marker.zt; //属性传值用来动态传弹窗内容
    //鼠标点击marker弹出自定义的信息窗体
    markerss.on("click", openInfo);
    //鼠标经过事件
    markerss.on("mouseover", openInfo); //移入Marker
    markerss.on("mouseout", setnum); //移出Marker 用来做发送请求防抖
    // 第一个参数为空,表明用图上所有覆盖物 setFitview
    // 第二个参数为false, 非立即执行
    // 第三个参数设置上左下右的空白
    markerss.setMap(map); //把点再地图上
    // map.setFitView(null, false, [20, 20, 20, 30]);
  });
};
</script>
//===========注意!! marker样式设置不能 scope样式隔离===========
<style lang="scss">
#container {
  width: 100%;
  height: 100%;
  .amap-marker-label {
    border: 1px solid #ccc;
	//标签的样式官方有文档
    border-radius: 5px;
    // background-color: transparent;
    background-color: #f7f7f7;
  }
  .info {
    color: rgb(97, 97, 197);
  }
  .inputEnd {
    color: #2d7ad6;
  }
}
//下面就是两个不同颜色Marker点的样式
.alert1 {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #ff0000;
  margin: auto 5px;
  animation: animation1 1s infinite;
}
/*高德地图标注动画*/
@keyframes animation1 {
  0% {
    -moz-box-shadow: 0px 0px 10px 5px #ff0000;
    box-shadow: 0px 0px 10px 5px #ff0000;
  }
  50% {
    -moz-box-shadow: 0px 0px 20px 5px #ff0000;
    box-shadow: 0px 0px 20px 5px #ff0000;
  }
  100% {
    -moz-box-shadow: 0px 0px 10px 5px #ff0000;
    box-shadow: 0px 0px 10px 5px #ff0000;
  }
  150% {
    -moz-box-shadow: 0px 0px 50px 5px #ff0000;
    box-shadow: 0px 0px 50px 5px #ff0000;
  }
}

.alert2 {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #00e921;
  margin: auto 5px;
  animation: animation2 1s infinite;
}

@keyframes animation2 {
  0% {
    -moz-box-shadow: 0px 0px 10px 5px #00e921;
    box-shadow: 0px 0px 10px 5px #00e921;
  }
  50% {
    -moz-box-shadow: 0px 0px 20px 5px #00e921;
    box-shadow: 0px 0px 20px 5px #00e921;
  }
  100% {
    -moz-box-shadow: 0px 0px 10px 5px #00e921;
    box-shadow: 0px 0px 10px 5px #00e921;
  }
  150% {
    -moz-box-shadow: 0px 0px 50px 5px #00e921;
    box-shadow: 0px 0px 50px 5px #00e921;
  }
}
.alert0 {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #656565;
  margin: auto 5px;
}
</style>

动态 Marker 点
//在接收到新数据后直接调用抽离的createMarker()
//例  markers 根据WebSocket返回的数据刷新
// var markers: any = ref([]);
// if (window.WebSocket) {
//   var ws = new WebSocket("ws://localhost:8000");

//   ws.onopen = function (e) {
//     console.log("连接服务器成功");
//     ws.send("index");
//   };
//   ws.onclose = function (e) {
//     console.log("服务器关闭");
//   };
//   ws.onerror = function () {
//     console.log("连接出错");
//   };

//   ws.onmessage = function (e) {
//     markers.value.splice(0);
//     let arr: any = JSON.parse(e.data);
//     markers.value.push(...arr);
//     //刷新marker点
//     createMarker();
//   };
// }

弹窗 Marker 点跳转 地理位置逆向解析 infoWindow 自定义信息框 事件交互 完整代码

<script setup lang="ts">
//开发技术   vue3 pinia  ts
import { ref, watch } from "vue";
import AMapLoader from "@amap/amap-jsapi-loader"; //引入地图
import { onMounted } from "vue"; //地图需要挂载在onMounted钩子
import { shallowRef } from "@vue/reactivity"; //改变监听
import axios from "axios"; //单独配置高德地图逆向解析经纬度请求 就直接用原生axios发送了
let showInfo = 0; //控制InfoWindow弹窗防抖 因为鼠标放上Marker点后 一直触发鼠标移入事件 用这个配合鼠标移出事件达到防抖

//用websocket实时推送
//动态数据
// var markers: any = ref([]);
// if (window.WebSocket) {
//   var ws = new WebSocket("ws://localhost:8000");

//   ws.onopen = function (e) {
//     console.log("连接服务器成功");
//     ws.send("index");
//   };
//   ws.onclose = function (e) {
//     console.log("服务器关闭");
//   };
//   ws.onerror = function () {
//     console.log("连接出错");
//   };

//   ws.onmessage = function (e) {
//     markers.value.splice(0);
//     let arr: any = JSON.parse(e.data);
//     markers.value.push(...arr);
//     //动态刷新marker点
//     createMarker();
//   };
// }

//死数据
var markers = ref([
  {
    carNum: "桂LMM267",
    in: "alert0",
    position: [113.821215, 22.607418],
    zt: "离线",
  },
  {
    carNum: "粤LMM267",
    in: "alert1",
    position: [116.368904, 45.913423],
    zt: "运动",
  },
  {
    carNum: "粤LMM267",
    in: "alert2",
    position: [116.305467, 30.807761],
    zt: "静止",
  },
  {
    carNum: "粤LMM267",
    in: "alert0",
    position: [126.205467, 39.907761],
    zt: "静止",
  },
  {
    carNum: "粤LMM267",
    in: "alert1",
    position: [108.878913, 35.210191],
    zt: "静止",
  },
  {
    carNum: "粤LMM997",
    in: "alert1",
    position: [106.205467, 39.907761],
    zt: "静止",
  },
  {
    carNum: "粤KLM267",
    in: "alert0",
    position: [102.706709, 25.047415],
    zt: "静止",
  },
]);

var map: any = shallowRef(null); //设置监听

let positionCn: any = ref(""); //转换后的地址中文
//点归位置
const outMarker = () => {
  //调用归位点
  // 第一个参数为空,表明用图上所有覆盖物 setFitview
  // 第二个参数为false, 非立即执行
  // 第三个参数设置上左下右的空白
  map.setFitView(null, false, [150, 60, 100, 60]);
};

//多个标记点 数据
//0离线,1运动,2静止

//点事件弹窗抽离出来包括移动中心点
//移出事件配合下面的发请求
let setnum = () => {
  num = 0;
};

var openInfo = (e) => {
  showInfo++;

  if (showInfo == 1) {
    let positionCar = e.target._position;
    console.log(e.type);

    console.log("发送了请求");

    //防抖 发请求获取逆向地理位置
    axios
      .get(
        `https://restapi.amap.com/v3/geocode/regeo?key=你的密钥&location=${positionCar[0]},${positionCar[1]}&poitype=地名地址信息&radius=100&extensions=all&batch=false&roadlevel=0`
      )
      .then((res) => {
        positionCn.value = res.data.regeocode.formatted_address;
      });

    //逆向地理查询
    //根据请求逆向编码地址

    //用watch监听 中文地址 因为是异步返回的 所以监听到值改变后 再创建弹窗
    watch(positionCn, () => {
      var info: any = [];
      info.push(
        '<div class=\'input-card content-window-card\'><div><img style="float:left;" src=" https://webapi.amap.com/images/autonavi.png "/></div> '
      );
      info.push('<div  style="padding:7px 0px 0px 0px;" color: red><h4>速度</h4>');
      info.push(
        `<p class='input-item' style='color: red;'>地址:${positionCn.value}</p></div></div>`
      );
      info.push(`<p class='inputEnd' >状态:${e.target.orderno}</p></div></div>`);
      info.push(`<button onclick="getLen()">发送请求</button>`); //点击事件
      //@ts-ignore
      let infoWindow = new AMap.InfoWindow({
        autoMove: true,
        closeWhenClickMap: true,
        content: info.join(""), //使用默认信息窗体框样式,显示信息内容
        //@ts-ignore
        offset: new AMap.Pixel(0, -30),
      });
      //@ts-ignore
      //第二参数表示展示的位置
      infoWindow.open(map, e.target.getPosition());
    });
    // infoWindow.open(map, e.target.getPosition());
    //构建信息窗体中显示的内容
    //如果是点击事件就跳转
  }
  if (e.type === "click") {
    // //中心点跳转
    map.setZoomAndCenter(15, e.target.getPosition());
  }
};
//Marker创建抽离
const createMarker = () => {
  //@ts-ignore
  map.clearMap(); // 清除地图覆盖物
  markers.value.forEach(async function (marker: any) {
    //@ts-ignore
    let markerss = await new AMap.Marker({
      resizeEnable: true,
      map: map,
      content: `<div class="${marker.in}" style='color: red;'></div>`,
      position: [marker.position[0], marker.position[1]], //@ts-ignore
      offset: new AMap.Pixel(-13, -30),
    });
    await markerss.setLabel({
      direction: "centre",
      //@ts-ignore
      offset: new AMap.Pixel(0, 50), //设置文本标注偏移量
      content: `<div class='info'>${marker.carNum}</div>`, //设置文本标注内容
    });

    markerss.orderno = marker.zt; //传值

    //   //   //鼠标点击marker弹出自定义的信息窗体
    markerss.on("click", openInfo);
    //鼠标经过事件
    markerss.on("mouseover", openInfo); //移入Marker
    markerss.on("mouseout", setnum); //移出Marker 用来做发送请求防抖
    // 第一个参数为空,表明用图上所有覆盖物 setFitview
    // 第二个参数为false, 非立即执行
    // 第三个参数设置上左下右的空白
    markerss.setMap(map); //把点再地图上
    // map.setFitView(null, false, [20, 20, 20, 30]);
  });
};
// watch(markers, () => {
//   console.log(1231);

// });

const initMap = () => {
  //@ts-expect-error
  window._AMapSecurityConfig = { securityJsCode: "你的密钥" };
  AMapLoader.load({
    key: "你的密钥", // 申请好的Web端开发者Key,首次调用 load 时必填
    version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
    plugins: ["AMap.Geocoder", "AMap.Geolocation", "AMap.ControlBar"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
  }) //container容器
    .then((AMap) => {
      map = new AMap.Map("container", {
        //设置地图容器id
        viewMode: "3D", //是否为3D地图模式
        mapStyle: "amap://styles/dd878847b26aa456c92b21c23de177d3",
        zoom: 4.8,
        center: [106.577823, 33.168496],

        //zoom: 8, //初始化地图级别
        //center: [113.83804, 22.62621], //初始化地图中心点位置
        //mapStyle: "amap://styles/darkblue", //设置样式
      });

      //创建Marker点
      createMarker();
    })
    .catch((e) => {
      console.log(e); //错误打印
    });
};

onMounted(() => {
  initMap(); //调用这个高德地图
});
//@ts-ignore
window.getLen = () => {
  //弹窗点击事件调用
  console.log("22222");
};
</script>

<template>
  <div class="all">
    <button onclick="infoClick()"></button>
    <div id="container"></div>
    <button class="btn" @click="outMarker">marker归位</button>
  </div>
</template>

<style lang="scss">
.all {
  position: relative;
  width: 100%;
  height: 100%;
}
#container {
  width: 100%;
  height: 100%;
  .amap-marker-label {
    border: 1px solid #ccc;

    border-radius: 5px;
    // background-color: transparent;
    background-color: #f7f7f7;
  }
  .info {
    color: rgb(97, 97, 197);
  }
  .inputEnd {
    color: #2d7ad6;
  }
}
.btn {
  position: absolute;
  top: 20px;
  z-index: 9999;
  color: red;
}
.alert1 {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #ff0000;
  margin: auto 5px;
  animation: animation1 1s infinite;
}
/*高德地图标注动画*/
@keyframes animation1 {
  0% {
    -moz-box-shadow: 0px 0px 10px 5px #ff0000;
    box-shadow: 0px 0px 10px 5px #ff0000;
  }
  50% {
    -moz-box-shadow: 0px 0px 20px 5px #ff0000;
    box-shadow: 0px 0px 20px 5px #ff0000;
  }
  100% {
    -moz-box-shadow: 0px 0px 10px 5px #ff0000;
    box-shadow: 0px 0px 10px 5px #ff0000;
  }
  150% {
    -moz-box-shadow: 0px 0px 50px 5px #ff0000;
    box-shadow: 0px 0px 50px 5px #ff0000;
  }
}

.alert2 {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #00e921;
  margin: auto 5px;
  animation: animation2 1s infinite;
}

@keyframes animation2 {
  0% {
    -moz-box-shadow: 0px 0px 10px 5px #00e921;
    box-shadow: 0px 0px 10px 5px #00e921;
  }
  50% {
    -moz-box-shadow: 0px 0px 20px 5px #00e921;
    box-shadow: 0px 0px 20px 5px #00e921;
  }
  100% {
    -moz-box-shadow: 0px 0px 10px 5px #00e921;
    box-shadow: 0px 0px 10px 5px #00e921;
  }
  150% {
    -moz-box-shadow: 0px 0px 50px 5px #00e921;
    box-shadow: 0px 0px 50px 5px #00e921;
  }
}
.alert0 {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #656565;
  margin: auto 5px;
}
</style>