(相关资料图)
在我们使用高德地图的时候,官方给我们推荐了很多案例,demo
,但是这些案例都是使用原生方法接入,并没有提供vue
或者react
的demo
,vue2
的 接入网上也很多人都有写过,下面本篇文章就来看看 vue3
怎么使用常用的高德地图api
,希望对大家有所帮助!
前置工作
首先安装包并引入npm i @amap/amap-jsapi-loader --save
登录后复制
import AMapLoader from "@amap/amap-jsapi-loader"
登录后复制
使用官方介绍的方式进行加
vue2
和 vue3
是有区别的,这里我们使用的是 vue3
,但这里 vue3
的方式还是选项式,不是组合式的,我自己写的时候使用的是组合式的,且集成了ts
, 我后面发布完整 .vue
文件的时候 会去掉标签上的 ts,因为类型还没有完善,等后面完善了再贴更改以后得。为什么要使用 shallowRef
官方也给出了说明原因。 【相关推荐:vuejs视频教程、web前端开发】
示例模块
模块的引入
首先导入的方式,和官网一样,后面我会贴完整代码, 这里我们使用plugins
加载插件, 其他配置如 Loca
, 直接进行配置, 这里需要注意版本问题, 写成 ‘2.0’ 是不行的,初始化函数在 onmounted
生命周期中执行。AMap存储这里我做了很多存储,大家知道 .value
的语法是 vue3
获取 ref
的语法,我下面使用到的 都是ref
,后面完整代码可以查看, 这里挂载的时候直接存一下,因为很多工具方法都会只用到他,这里后期业务逻辑我会抽离到 pinia
中去,所以不需要在初始化函数中写全部的业务逻辑。模版样式不生效问题, 我们在使用的时候, 就像我之前写的文章,点位新增的时候,我们会插入 content
字符串模版,替换点样式,这里有两种方案修改样式,一种是 插入 DOM
,不使用字符串,然后在 DOM
上通过 style
直接修改样式,另一种就是使用模版的时候直接给 class
类名,但是这种样式如果我们给 vue
的 style
加了 scoped
就不会生效,这里大家可以自己灵活选择用哪种,我这里暂时先使用模版的方式,去掉了 scoped
。图例, 图例这里除了导入的时候,需要配置一下,使用上来说变化不大,样式的修改还是复用了我之前的逻辑。import AMapLoader from "@amap/amap-jsapi-loader"const initMap = () => { AMapLoader.load({ key: "b59c490f61a694b9d7576dd864f74d6e", // 申请好的Web端开发者Key,首次调用 load 时必填 version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15 plugins: ["AMap.Scale", "AMap.ToolBar", "AMap.MouseTool"], // 需要使用的的插件列表,如比例尺"AMap.Scale"等 Loca:{ version:"2.0.0" } }) .then((res) => { AMap.value = res // 上来就显示的中心点 北京 116.397, 39.918 var lnglat = new res.LngLat(105, 38) map.value = new res.Map("container", { //设置地图容器id viewMode: "3D", //是否为3D地图模式 zoom: 5, //初始化地图级别 center: lnglat, //初始化地图中心点位置 }) map.value.clearMap() // 清除地图覆盖物 // 地图是否可拖拽和缩放 map.value.setStatus({ dragEnable: true, // 是否可拖拽 zoomEnable: true, // 是否可缩放 }) initWindow() // 添加一些分布不均的点到地图上,地图上添加三个点标记,作为参照 coordData.forEach(function (marker) { setMarker(marker) }) let renderLine = setLine(coordData) // 设置线 let polyline = renderLine.reduce((prev, item, index) => { let weight = item.type === 1 ? 5 : 3 let color = item.type === 1 ? headColors[0] : headColors[1] prev.push(setLines(item.current, color, weight)) return prev }, []) map.value.add([...polyline]) // 绘制线 //创建右键菜单 menuInstance.value = new ContextMenu(map.value) let loca = new Loca.Container({ map:map.value, }); window._loca = loca; // 图例, 图例可以实例化多个,使用定位来设置位置 let lengend = new Loca.Legend({ loca: loca, title: { label: "管道类型", fontColor: "rgba(255,255,255,1)", fontSize: "16px" }, style: { backgroundColor: "rgba(255,255,255,0.2)", left: "20px", bottom: "40px", fontSize: "12px" }, dataMap: [ { label: "省级管道", color: headColors[1] }, { label: "县级管道", color: headColors[0] }, ], }); //修改图例排列方式 document.getElementsByClassName("amap-loca loca-controls")[0].setAttribute("id", "testid") var lis = document.querySelectorAll("#testid li"); for (var i = 0; i < lis.length; i++) { console.log(lis[i]); lis[i].setAttribute("class", "test" ); } }) .catch((e) => { console.log("error", e) })}onMounted(() => { initMap()})
登录后复制
右键菜单
这里使用了一个函数,但这个函数还不是类,但是他却在里面使用了this
,实话来讲,这种写法确实不是很优秀,可扩展性很差,不够健壮,但没办法,谁让我们用了人家的东西呢是吧, 在 vue3
中这么用就不可以了,首先 vue3
里面使用 this
就不是官方建议的, 另外这里面还修改了函数原型上的方法,其实我得代码里面一共有两种右键菜单,如下:一种是在指定点位上打开,另一种是在非点位的空白处打开,指定点位处打开的其实叫信息窗体,只不过是通过右键的方式触发,那个没有上面这个右键菜单麻烦。
首先来说this
问题, 这里的 this
实际上就是把我们的实例化对象挂载到上面而已,vue3
中没办法像 vue2
那样使用 this
, 但也提供给我们了 api
来获取当前组件的实例化对象, 然后我没用使用函数, 使用了一个类,类构造这个方法, 模版也不适用字符串模版,因为这里字符串模版的事件绑定写死了,我们使用 DOM
来动态绑定事件,代码如下:const { ctx } = getCurrentInstance()const _this = ctx//自定义菜单类class ContextMenu { constructor(map) { var me = _this //地图中添加鼠标工具MouseTool插件 _this.mouseTool = new AMap.value.MouseTool(map) _this.contextMenuPositon = null const fragment = document.createElement("div") // 使用 DOM 方式, 方便添加事件 fragment.className = "info context_menu" const p = document.createElement("p") p.addEventListener("click", this.delMarkerMenu) p.textContent = "移除上次选中信息" fragment.appendChild(p) //通过content自定义右键菜单内容 _this.contextMenu = new AMap.value.ContextMenu({ isCustom: true, content: fragment, }) //地图绑定鼠标右击事件——弹出右键菜单 map.on("rightclick", function (e) { me.contextMenu.open(map, e.lnglat) me.contextMenuPositon = e.lnglat //右键菜单位置 }) } delMarkerMenu() { // 右键菜单上次选中点的信息 clearPoint() _this.mouseTool.close() _this.contextMenu.close() }}
登录后复制
完整代码
添加选点请输入坐标
<script setup>import { onMounted, reactive, ref, getCurrentInstance } from "vue"import AMapLoader from "@amap/amap-jsapi-loader"import { shallowRef } from "vue"import { coordData } from "./data"const map = shallowRef(null)const { ctx } = getCurrentInstance()const _this = ctxconst menuInstance = ref() // menu 实例let AMap = ref() // map 实例let currentPonit = ref(null) // 存储当前选中点 DOMlet currentData = reactive({}) // 当前选重点信息let sourceInfoWindow = ref()const headColors = ["#3366bb", "#6622FF"]// 工具方法// 修改DOM 类名function changeStyle(res, data) { if (currentPonit.value !== null) { currentPonit.value.classList.remove("active") } currentPonit.value = res.children[0] currentData = data currentPonit.value.classList.add("active")}// 清除点信息function clearPoint() { if (currentPonit.value) { currentPonit.value.classList.remove("active") } currentPonit.value = null currentData = {}}// 设置线信息function setLines(lnglat, color, weight) { return new AMap.value.Polyline({ path: lnglat, // showDir:true ,// 设置线方向 strokeColor: color, // 线颜色 strokeWeight: weight, // 线宽 strokeOpacity: 0.6, // 透明度 })}function markerClick(e) { console.log("sourceInfoWindow.value", sourceInfoWindow.value, e.target) sourceInfoWindow.value.setContent(e.target.contents) sourceInfoWindow.value.open(map.value, e.target.getPosition())}function setInput(e, name) { let text = e.target.parentElement.parentElement.children[0].innerText.split( "供给点", )[0] let current = coordData.filter((item) => { return item.name === text }) window.localStorage.setItem(text + name, e.target.value)}const initWindow = () => { // 信息窗体 let infoWindow = new AMap.value.InfoWindow({ offset: new AMap.value.Pixel(0, -10), retainWhenClose: true, }) sourceInfoWindow.value = infoWindow infoWindow.on("open", function (...arg) { let inputOut = document.getElementById("inputOut") let inputPro = document.getElementById("inputPro") inputOut.addEventListener("change", (e) => { setInput(e, "inputOut") window.location.reload() }) inputPro.addEventListener("change", (e) => { setInput(e, "inputPro") window.location.reload() }) })}// 抽离点位信息设置function setMarker(marker) { //创建右键菜单 var contextMenu = new AMap.value.ContextMenu() //右键放大 contextMenu.addItem( "放大一级", function () { map.value.zoomIn() }, 0, ) //右键缩小 contextMenu.addItem( "缩小一级", function () { map.value.zoomOut() }, 1, ) contextMenu.addItem("设置起点", function () { console.log("设置起点", marker, markerd.dom) changeStyle(markerd.dom, marker) contextMenu.close() // 关闭右键菜单 }) contextMenu.addItem("与起点连线", function () { if (!currentPonit) { alert("请选择起点") contextMenu.close() return } else { // 这里其实可以根据数据判定线类型了,因为第二个选中点的信息+和第一个选中点的信息都有了,但是过滤方法会比较复杂 let path = [currentData.position, marker.position] const polyline1 = setLines(path, "#3366bb", 5) map.value.add([polyline1]) clearPoint() } contextMenu.close() // 关闭右键菜单 }) let content = "" var markerd = new AMap.value.Marker({ map: map.value, // icon: marker?.icon, content, offset: new AMap.value.Pixel(-8, -8), visible: true, // 点标记是否可见 position: [marker.position[0], marker.position[1]], }) let inputO = window.localStorage.getItem(marker.name + "inputOut") let inputP = window.localStorage.getItem(marker.name + "inputPro") // 左键点击的信息窗体, 宽度会在碰触到容器边缘的时候自适应的缩小 markerd.contents = ` ${marker.name}供给点 出口压力:kPa 供给量:m³ 位置:经度${marker.position[0]},纬度${marker.position[1]}` markerd.data = marker markerd.on("click", markerClick) if (marker.name === "新疆") { // 触发上面的点击事件 markerd.emit("click", { target: markerd }) } //绑定鼠标右击事件——弹出右键菜单 markerd.on("rightclick", function (e) { contextMenu.open(map.value, e.lnglat) }) return markerd}//自定义菜单类class ContextMenu { constructor(map) { var me = _this //地图中添加鼠标工具MouseTool插件 _this.mouseTool = new AMap.value.MouseTool(map) _this.contextMenuPositon = null const fragment = document.createElement("div") // 使用 DOM 方式, 方便添加事件 fragment.className = "info context_menu" const p = document.createElement("p") p.addEventListener("click", this.delMarkerMenu) p.textContent = "移除上次选中信息" fragment.appendChild(p) //通过content自定义右键菜单内容 _this.contextMenu = new AMap.value.ContextMenu({ isCustom: true, content: fragment, }) //地图绑定鼠标右击事件——弹出右键菜单 map.on("rightclick", function (e) { me.contextMenu.open(map, e.lnglat) me.contextMenuPositon = e.lnglat //右键菜单位置 }) } delMarkerMenu() { // 右键菜单上次选中点的信息 clearPoint() _this.mouseTool.close() _this.contextMenu.close() }}// 过滤线方法function setLine(arr) { return arr.reduce((prev, item) => { if (item?.line) { prev.push(...item.line) } return prev }, [])}const initMap = () => { AMapLoader.load({ key: "b59c490f61a694b9d7576dd864f74d6e", // 申请好的Web端开发者Key,首次调用 load 时必填 version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15 plugins: ["AMap.Scale", "AMap.ToolBar", "AMap.MouseTool"], // 需要使用的的插件列表,如比例尺"AMap.Scale"等 Loca:{ version:"2.0.0" } }) .then((res) => { AMap.value = res // 上来就显示的中心点 北京 116.397, 39.918 var lnglat = new res.LngLat(105, 38) map.value = new res.Map("container", { //设置地图容器id viewMode: "3D", //是否为3D地图模式 zoom: 5, //初始化地图级别 center: lnglat, //初始化地图中心点位置 }) map.value.clearMap() // 清除地图覆盖物 // 地图是否可拖拽和缩放 map.value.setStatus({ dragEnable: true, // 是否可拖拽 zoomEnable: true, // 是否可缩放 }) initWindow() // 添加一些分布不均的点到地图上,地图上添加三个点标记,作为参照 coordData.forEach(function (marker) { setMarker(marker) }) let renderLine = setLine(coordData) // 设置线 let polyline = renderLine.reduce((prev, item, index) => { let weight = item.type === 1 ? 5 : 3 let color = item.type === 1 ? headColors[0] : headColors[1] prev.push(setLines(item.current, color, weight)) return prev }, []) map.value.add([...polyline]) // 绘制线 //创建右键菜单 menuInstance.value = new ContextMenu(map.value) let loca = new Loca.Container({ map:map.value, }); window._loca = loca; // 图例, 图例可以实例化多个,使用定位来设置位置 let lengend = new Loca.Legend({ loca: loca, title: { label: "管道类型", fontColor: "rgba(255,255,255,1)", fontSize: "16px" }, style: { backgroundColor: "rgba(255,255,255,0.2)", left: "20px", bottom: "40px", fontSize: "12px" }, dataMap: [ { label: "省级管道", color: headColors[1] }, { label: "县级管道", color: headColors[0] }, ], }); //修改图例排列方式 document.getElementsByClassName("amap-loca loca-controls")[0].setAttribute("id", "testid") var lis = document.querySelectorAll("#testid li"); for (var i = 0; i < lis.length; i++) { console.log(lis[i]); lis[i].setAttribute("class", "test" ); } }) .catch((e) => { console.log("error", e) })}onMounted(() => { initMap()})</script>
登录后复制
这里的业务逻辑还不完善, 输入部分的交互逻辑没有完成, 这个文件直接引入自己的项目,安装一下上面说过的依赖, 就可以使用,不过这里数据源需要自己根据自己的数据来构造就可以了,我引入的事 data
中的一组假数据,在这里给大家两组看一下export const coordData = [ { name: "黑龙江", position: [127, 47], pointData: { out: 100, provide: 10, }, line: [ { current: [ [127, 47], [126, 43], ], type: 1, }, ], }, { name: "吉林", position: [126, 43], pointData: { out: 120, provide: 11, }, line: [ { current: [ [126, 43], [113, 41], ], type: 1, }, ], }, ]
登录后复制
后面我会把业务逻辑抽离到 pinia
中, 并且完善ts
类型, 大家对哪一部分有疑问或者更好的解决方案可以留言一起学习~(学习视频分享:vuejs入门教程、编程基础视频)
以上就是聊聊vue3中怎么使用高德地图api的详细内容,更多请关注php中文网其它相关文章!
关键词: