【每日一拳】打在 vue+高德地图api (@amap/amap 您所在的位置:网站首页 vue高德地图多个地点标注 【每日一拳】打在 vue+高德地图api (@amap/amap

【每日一拳】打在 vue+高德地图api (@amap/amap

2023-09-22 09:18| 来源: 网络整理| 查看: 265

前言

之前也有做过地图组件(貌似使用百度 api),但大多都是cv也没有去深究。

刚好之前公司有个项目需要点击地址跳转到地图页,在地图页显示相关地址信息,也借此机会重新学习了一下高德地图 api。

找了一下相关文档感觉也不是很详细,那就写点什么记录一下吧,开干!

目前而言,对于高德地图 api 的使用看到过三种方式:

引入 @amap/amap-jsapi-loader 引入原生的高德地图 api 引入 vue-amap @amap/amap-jsapi-loader

无意中在网上看到一个 @amap/amap-jsapi-loader 的高德地图依赖,有兴趣就去研究了一下。

npm 社区是下图这样描述的,但是 高德地图官方文档 感觉也不是很详细。

amap-jsapi-loader.jpg

所以也自己用 vue3 跑了一个 demo,小试一下。

1. 安装依赖并引入 pnpm install @amap/amap-jsapi-loader

然后在 components 下创建 Amap 组件并且引入之

import AMapLoader from "@amap/amap-jsapi-loader"; 2. 初始化地图

参照 官方文档 AMapLoader.load 方法参数说明

AMapLoader.load({ "key": "", // 申请好的Web端开发者Key,首次调用 load 时必填 "version": "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15 "plugins": [] // 需要使用的的插件列表,如比例尺'AMap.Scale'等 "AMapUI": { // 是否加载 AMapUI,缺省不加载 "version": '1.1', // AMapUI 缺省 1.1 "plugins":[], // 需要加载的 AMapUI ui插件 }, "Loca":{ // 是否加载 Loca, 缺省不加载 "version": '1.3.2' // Loca 版本,缺省 1.3.2 }, }).then(()=>{ window.AMap.xx; window.AMapUI.xx; window.Loca.xx });

使用 AMapLoader.load 来初始化渲染地图组件,使用 AMap.Map 类创建和展示地图对象。

let map; const mapConfigure = { amapKey: "", // 申请好的Web端开发者Key options: { resizeEnable: true, // 是否监控地图容器尺寸变化 center: [121.553958, 29.869472], // 初始地图中心点 zoom: 14, // 初始地图级别 } }; onBeforeMount(() => { if (!instance) return; let { options } = MapConfigure; AMapLoader.load({ key: mapConfigure.amapKey, version: "2.0", plugins: [], AMapUI: { version: "1.1", plugins: [] } }) .then(AMap => { // 创建地图实例 map = new AMap.Map(instance.refs.mapView, options); }) .catch(() => { throw "地图加载失败,请重新加载"; }); });

初始化地图.jpg

3. 使用 SimpleMarker 创建标记点

SimpleMarker(简单标注)继承自 AMap.Marker,在已有功能的基础上,额外增加如下的支持:

支持设置背景图标(iconTheme,iconStyle)和前景文字(iconLabel);背景图标内置若干样式可供挑选(如上方示例),也支持自定义图片地址或者Dom结构。 支持显示定位点,默认用红点标识(查看示例),红点的中心即是经纬度(即position)对应的位置。用于开发阶段,辅助开发者设置Marker图标相对于经纬度的显示偏移量。(即Marker的offset参数)

加载 SimpleMarker(模块名:ui/overlay/SimpleMarker)

AMapLoader.load({ key: mapConfigure.amapKey, version: "2.0", AMapUI: { version: "1.1", plugins: ["overlay/SimpleMarker"] // 需要加载的 AMapUI ui插件 } })

创建 SimpleMarker 实例

AMapLoader.load({ key: mapConfigure.amapKey, version: "2.0", AMapUI: { version: "1.1", plugins: ["overlay/SimpleMarker"] } }).then((AMap) => { map = new AMap.Map(instance.refs.mapView, options); // !!! 通过 AMap.SimpleMarker 获取组件 new AMapUI.SimpleMarker({ //前景文字 iconLabel: 'A', //图标主题 iconTheme: 'default', //背景图标样式 iconStyle: 'red', map: map, position: map.getCenter() }); }).catch((e) => { throw "地图加载失败,请重新加载"; });

marker1.jpg

可以更改标记点 marker 的样式,参考官方文档:lbs.amap.com/api/amap-ui…

AMapLoader.load({ key: mapConfigure.amapKey, version: "2.0", AMapUI: { version: "1.1", plugins: ["overlay/SimpleMarker"] } }).then((AMap) => { map = new AMap.Map(instance.refs.mapView, options); let marker = new AMapUI.SimpleMarker({ // 前景文字 // iconLabel: "天一", // 自定义图标地址 iconStyle: { src: "http://webapi.amap.com/theme/v1.3/markers/b/mark_r.png", style: { width: "20px", height: "30px" } }, // 设置基点偏移 // offset: new AMap.Pixel(0, -30), // showPositionPoint: true, map: map, position: map.getCenter(), }); }).catch((e) => { throw "地图加载失败,请重新加载"; });

marker2.jpg

4. 使用 SimpleInfoWindow 创建信息窗体

SimpleInfoWindow(简单信息窗体)继承自 AMap.InfoWindow,提供一种简单的“标题+内容”构造的信息窗体;内容的构建支持使用模板。

加载 SimpleInfoWindow(模块名:ui/overlay/SimpleInfoWindow)

AMapLoader.load({ key: mapConfigure.amapKey, version: "2.0", AMapUI: { version: "1.1", plugins: ["overlay/SimpleInfoWindow"] // 需要加载的 AMapUI ui插件 } })

创建 SimpleInfoWindow 实例,参考官方文档:lbs.amap.com/api/amap-ui…

AMapLoader.load({ key: mapConfigure.amapKey, version: "2.0", AMapUI: { version: "1.1", plugins: ["overlay/SimpleInfoWindow"] } }).then(AMap => { ………… let infoWindow = new AMapUI.SimpleInfoWindow({ infoTitle: '这里是标题', // 标题内容,html代码 infoBody: '

这里是内容。

', // 主体内容,html代码 }); infoWindow.open(map, map.getCenter()); map.add(infoWindow); // 添加图层到地图 }) .catch(() => { throw "地图加载失败,请重新加载"; });

自定义窗体内容

import square from "../../assets/images/square.jpeg"; const info = { name: "天一广场", address: "浙江省宁波市海曙区中山东路188号", phone: "(0574)87683088", time: "10:00-22:00", imageUrl: square }; AMapLoader.load({ key: mapConfigure.amapKey, version: "2.0", AMapUI: { version: "1.1", plugins: ["overlay/SimpleMarker", "overlay/SimpleInfoWindow"] } }).then(AMap => { ………… let infoWindow = new AMapUI.SimpleInfoWindow({ infoTitle: `${info.name}`, infoBody: instance.refs.infoWindow.innerHTML, offset: new AMap.Pixel(0, -40), // position: map.getCenter(), }); infoWindow.open(map, map.getCenter()); map.add(infoWindow); // 添加图层到地图 }) .catch(() => { throw "地图加载失败,请重新加载"; }); 地址:{{ info.address }} 电话:{{ info.phone }} 营业时间: {{ info.time }}

infoWindow.jpg

给 marker 添加点击事件,也可以给窗体内容绑定监听事件,参考文档:lbs.amap.com/demo/amap-u…

AMapLoader.load({ key: mapConfigure.amapKey, version: "2.0", AMapUI: { version: "1.1", plugins: ["overlay/SimpleMarker", "overlay/SimpleInfoWindow"] } }).then(AMap => { ………… const openInfoWin = () => { infoWindow.open(map, map.getCenter()); }; // marker 点击时打开 marker.on("click", function () { openInfoWin(); }); map.add(infoWindow); // 添加图层到地图 }) .catch(() => { throw "地图加载失败,请重新加载"; }); 5. 添加地图控件

在线插件是在基础地图服务上增加的额外功能,您可以根据自己的需要选择添加。插件分为两类:一类是地图控件,它们是用户与地图交互的UI元素,例如缩放控制条(ToolBar)等;一类是功能型插件,用来完成某些特定地图功能,比如鼠标工具(MouseTool)等。

控件名称说明是否插件AMap.ControlBar组合了旋转、倾斜、复位、缩放在内的地图控件,在3D地图模式下会显示(自V1.4.0版本新增)是AMap.MapType地图类型切换插件,用来切换固定的几个常用图层是AMap.OverView地图鹰眼插件,默认在地图右下角显示缩略图是AMap.Scale地图比例尺插件是AMap.ToolBar地图工具条插件,可以用来控制地图的缩放和平移是

可以参考官方文档:lbs.amap.com/api/javascr…

AMapLoader.load({ key: mapConfigure.amapKey, version: "2.0", plugins: ["AMap.MarkerCluster"], AMapUI: { version: "1.1", plugins: ["overlay/SimpleMarker", "overlay/SimpleInfoWindow"] } }).then(AMap => { ………… map.plugin( [ "AMap.ToolBar", "AMap.MapType", "AMap.Geolocation", "AMap.Scale", "AMap.ControlBar" ], // [], () => { // 地图工具条插件,可以用来控制地图的缩放和平移 map.addControl(new AMap.ToolBar()); // 地图类型切换插件,用来切换固定的几个常用图层 map.addControl( new AMap.MapType({ defaultType: 0 }) ); // 比例尺插件, 位于地图左下角 map.addControl(new AMap.Scale()); // map.addControl(new AMap.Geolocation()); map.addControl(new AMap.ControlBar()); } ); ………… }) .catch(() => { throw "地图加载失败,请重新加载"; }); });

地图控件.jpg

6. 选址组件

可以查看我的另一篇文章 《vue+高德地图api 封装选址组件》

7. 其他功能 PointSimplifier:是一个针对海量点展示场景的组件,能够支持较大规模的经纬度数据,以及配置丰富的展示效果。 MarkerCluster:使用 AMap.MarkerCluster 展示大量点标记,可灵活设定聚合样式。 ……

暂时没有去深究,以后有时间补上,通通补上。

8. 完整代码 import AMapLoader from "@amap/amap-jsapi-loader"; import { getCurrentInstance, onBeforeMount, onUnmounted } from "vue"; import square from "../../assets/images/square.jpeg"; interface MapConfigOption { resizeEnable?: boolean; center?: number[]; zoom?: number; } interface MapConfigure { amapKey: string; options: MapConfigOption; } interface MapConfigureInter { on: Fn; destroy?: Fn; clearEvents?: Fn; addControl?: Fn; getCenter?: Fn; setCenter?: Fn; setZoom?: Fn; plugin?: Fn; } let map: MapConfigureInter; const mapConfigure: MapConfigure = { amapKey: "b445fc42ae1593929170feca71b3e3b9", options: { resizeEnable: true, center: [121.553958, 29.869472], zoom: 14 } }; const instance = getCurrentInstance(); const info = { name: "天一广场", address: "浙江省宁波市海曙区中山东路188号", phone: "(0574)87683088", time: "10:00-22:00", imageUrl: square }; onBeforeMount(() => { if (!instance) return; let { options } = mapConfigure; AMapLoader.load({ key: mapConfigure.amapKey, version: "2.0", plugins: ["AMap.MarkerCluster"], AMapUI: { version: "1.1", plugins: ["overlay/SimpleMarker", "overlay/SimpleInfoWindow"] } }) .then(AMap => { // 创建地图实例 map = new AMap.Map(instance.refs.mapView, options); // 显示标记点 let marker = new AMapUI.SimpleMarker({ //前景文字 // iconLabel: "天一广场", //自定义图标地址 iconStyle: { src: "http://webapi.amap.com/theme/v1.3/markers/b/mark_r.png", style: { width: "20px", height: "30px" } }, // iconStyle: "lightblue", //设置基点偏移 // offset: new AMap.Pixel(0, -30), // showPositionPoint: true, map: map, position: map.getCenter() }); // 地图中添加地图操作ToolBar插件 map.plugin( [ "AMap.ToolBar", "AMap.MapType", "AMap.Geolocation", "AMap.Scale", "AMap.ControlBar" ], // [], () => { // 地图工具条插件,可以用来控制地图的缩放和平移 map.addControl(new AMap.ToolBar()); // 地图类型切换插件,用来切换固定的几个常用图层 map.addControl( new AMap.MapType({ defaultType: 0 }) ); // 比例尺插件, 位于地图左下角 map.addControl(new AMap.Scale()); // map.addControl(new AMap.Geolocation()); map.addControl(new AMap.ControlBar()); } ); let infoWindow = new AMapUI.SimpleInfoWindow({ infoTitle: `${info.name}`, infoBody: instance.refs.infoWindow.innerHTML, offset: new AMap.Pixel(0, -40) // position: map.getCenter(), }); infoWindow.open(map, map.getCenter()); const openInfoWin = () => { infoWindow.open(map, map.getCenter()); }; // marker 点击时打开 marker.on("click", function () { openInfoWin(); }); map.add(infoWindow); // 添加图层到地图 }) .catch(() => { throw "地图加载失败,请重新加载"; }); }); onUnmounted(() => { if (map) { // 销毁地图实例 map.destroy() && map.clearEvents("click"); } }); 地址:{{ info.address }} 电话:{{ info.phone }} 营业时间: {{ info.time }} #mapView { height: calc(100vh - 86px); } .info { display: none; } :deep(.amap-marker-label) { border: none !important; } 引入原生的高德 api 1. vue2 + 移动端 1.1 初始化地图

在 components 下创建 Amap 组件,使用 标签导入高德地图 api。

import { mapState } from "vuex"; let map = null; let infoWindow = null; export default { name: "map-view", computed: { ...mapState(["info"]), }, mounted() { const amap_key = '', cb = "amap_callback"; const scriptUrl = `https://webapi.amap.com/maps?v=1.4.18&key=${amap_key}&callback=${cb}`; // 导入script importScript(scriptUrl); window[cb] = () => { // 初始化地图 this.initMap(); }; }, methods: { initMap() { const info = this.info; const position = [info.longitude, info.latitude]; map = new AMap.Map("map-view", { resizeEnable: true, zoom: 15, center: position, }); AMap.plugin( ["AMap.ToolBar", "AMap.Geolocation", "AMap.Scale"], function () { map.addControl(new AMap.ToolBar()); map.addControl(new AMap.Scale()); map.addControl(new AMap.Geolocation()); } ); }, } }; 1.2 添加 marker 标记和信息窗口 {{ info.name }} 地址:{{ info.address | defaultInfo }} 电话:{{ info.phone | defaultInfo }} 营业时间: {{ info.time | defaultInfo }} methods: { initMap() { ………… let marker = new AMap.Marker({ title: info.address, position, map }); // 自定义窗体 infoWindow = new AMap.InfoWindow({ isCustom: true, content: this.$refs["infoWindow"], offset: new AMap.Pixel(0, -50), }); infoWindow.open(map, position); let closeBtn = document.querySelector(".info-close"); marker.on("click", this.closeHandler); }, closeHandler() { const info = this.info; const position = [info.longitude, info.latitude]; if (infoWindow.getIsOpen()) { infoWindow.close(); return; } infoWindow.open(map, position); }, } #mapView { position: relative; height: 100%; width: 100%; min-height: 500px; .info { position: relative; border: solid 1px silver; max-width: 270px; &-head { display: flex; position: relative; background: #f9f9f9; height: 30px; border-bottom: 0.5px solid #ccc; border-radius: 5px 5px 0 0; padding: 0 5px; align-items: center; justify-content: space-between; .info-title { flex: 1; max-width: 200px; font-size: 14px; font-weight: 500; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } } &-body { display: flex; background: #ffffff; font-size: 12px; padding: 6px; line-height: 20px; .info-img-wrap { width: 100px; height: 80px; margin-right: 5px; flex-shrink: 0; .info-img { width: 100%; height: 100%; } } p { word-break: break-all; } } } } 1.3 完整代码 {{ info.name }} 地址:{{ info.address | defaultInfo }} 电话:{{ info.phone | defaultInfo }} 营业时间: {{ info.time | defaultInfo }} import square from "../assets/img/square.jpeg"; import { mapState } from "vuex"; let infoWindow = null; let map = null; export default { name: "map-view", computed: { ...mapState(["info"]), }, mounted() { const amap_key = '', cb = "amap_callback"; const scriptUrl = `https://webapi.amap.com/maps?v=1.4.18&key=${amap_key}&callback=${cb}`; // 导入script importScript(scriptUrl); window[cb] = () => { // 初始化地图 this.initMap(); }; }, methods: { initMap() { const info = this.info; const position = [info.longitude, info.latitude]; map = new AMap.Map("mapView", { resizeEnable: true, zoom: 15, center: position, }); AMap.plugin( ["AMap.ToolBar", "AMap.Geolocation", "AMap.Scale"], function () { map.addControl(new AMap.ToolBar()); map.addControl(new AMap.Scale()); map.addControl(new AMap.Geolocation()); } ); // 自定义窗体 infoWindow = new AMap.InfoWindow({ isCustom: true, content: this.$refs["infoWindow"], offset: new AMap.Pixel(0, -50), }); infoWindow.open(map, arr); let closeBtn = document.querySelector(".info-close"); marker.on("click", this.closeHandler); }, closeHandler() { const info = this.info; const position = [info.longitude, info.latitude]; if (infoWindow.getIsOpen()) { infoWindow.close(); return; } infoWindow.open(map, position); }, }, }; function importScript(sSrc, success) { function loadError(err) { throw new URIError("The script " + err.target.src + " is not accessible."); } var oScript = document.createElement("script"); oScript.type = "text\/javascript"; oScript.onerror = loadError; if (success) oScript.onload = success; document.body.appendChild(oScript); oScript.src = sSrc; } #mapView { position: relative; height: 100%; width: 100%; min-height: 500px; .info { position: relative; border: solid 1px silver; max-width: 270px; &-head { display: flex; position: relative; background: #f9f9f9; height: 30px; border-bottom: 0.5px solid #ccc; border-radius: 5px 5px 0 0; padding: 0 5px; align-items: center; justify-content: space-between; .info-title { flex: 1; max-width: 200px; font-size: 14px; font-weight: 500; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } } &-body { display: flex; background: #ffffff; font-size: 12px; padding: 6px; line-height: 20px; .info-img-wrap { width: 100px; height: 80px; margin-right: 5px; flex-shrink: 0; .info-img { width: 100%; height: 100%; } } p { word-break: break-all; } } } }

引入原生的高德api.jpg

2. vue3 + pc端

这个本人没有去深入研究,在 githug 一个项目上看到过,都是导入 script 标签,大致效果也是一样的,也顺便贴一下代码,有兴趣的可以自己去研究哈。

组件代码:

import { defineComponent, ref, nextTick, unref, onMounted } from 'vue'; import { useScript } from '/@/hooks/web/useScript'; const A_MAP_URL = 'https://webapi.amap.com/maps?v=2.0&key=申请好的Web端开发者Key'; export default defineComponent({ name: 'AMap', props: { width: { type: String, default: '100%', }, height: { type: String, default: 'calc(100vh - 78px)', }, }, setup() { const wrapRef = ref(null); const { toPromise } = useScript({ src: A_MAP_URL }); async function initMap() { await toPromise(); await nextTick(); const wrapEl = unref(wrapRef); if (!wrapEl) return; const AMap = (window as any).AMap; new AMap.Map(wrapEl, { zoom: 11, center: [116.397428, 39.90923], viewMode: '3D', }); } onMounted(() => { initMap(); }); return { wrapRef }; }, });

hooks 文件:

import { onMounted, onUnmounted, ref } from 'vue'; interface ScriptOptions { src: string; } export function useScript(opts: ScriptOptions) { const isLoading = ref(false); const error = ref(false); const success = ref(false); let script: HTMLScriptElement; const promise = new Promise((resolve, reject) => { onMounted(() => { script = document.createElement('script'); script.type = 'text/javascript'; script.onload = function () { isLoading.value = false; success.value = true; error.value = false; resolve(''); }; script.onerror = function (err) { isLoading.value = false; success.value = false; error.value = true; reject(err); }; script.src = opts.src; document.head.appendChild(script); }); }); onUnmounted(() => { script && script.remove(); }); return { isLoading, error, success, toPromise: () => promise, }; } vue-amap

另一种使用 vue-amap 这个依赖的也人较多,但是 npm 社区最近的一次更新已经是三年前的事情了,而且 vue-amap 是一套基于 Vue 2.0 和高德地图的地图组件,如果使用 vue3 开发这个依赖就已经不适用了。

1. 安装依赖

首先在 main.js 引入依赖,然后使用 Vue.use 调用,并初始化 vue-amap

// 高德地图 import Amap from "vue-amap"; Vue.use(Amap); Amap.initAMapApiLoader({ key: "", // 申请好的Web端开发者Key plugin: [ // 插件集合 "AMap.Autocomplete", "AMap.PlaceSearch", "AMap.Scale", "AMap.OverView", "AMap.ToolBar", "AMap.MapType", "AMap.PolyEditor", "AMap.CircleEditor", ], // 默认高德 sdk 版本为 1.4.4 v: "1.4.4", }); 2. 引用组件

vue-amap地图.jpg

写在最后

无论什么方法,只要可以实现最终的诉求都是一个好方法,都值得一试。

接下来我也会继续去深究更多的东西,向大佬们看齐,也希望大家喜欢。

likeNum++;

readingQuantity++;

加油!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有