- 前端
- UI组件
- GIS
【免费下载链接】vue-amap
🌍 基于 Vue 2.x 和高德地图的地图组件
vue-amap 基于 Vue 2.x 封装了高德地图 JS API,其中el-amap-polygon组件用于在地图上绘制多边形区域(行政区划、商圈范围、地理围栏等场景)。本文以官方文档中的多边形页面为主体,完整覆盖其静态属性、动态属性、ref 方法与事件清单,并结合src/lib目录下的真实源码,深入讲解该组件的响应式监听机制、编辑器(PolyEditor)事件绑定原理以及AMapManager管理实例的调用链,帮助你在项目中快速落地并正确维护多边形覆盖物。
一、快速开始:一个可运行的多边形示例
官方文档给出的基础示例展示了多边形最典型的用法:地图内通过v-for渲染多个el-amap-polygon,并通过amap-manager统一管理实例。将示例整理为可直接复制到 Vue 项目中的写法如下:
<template> <div> <el-amap vid="amap" :zoom="zoom" :amap-manager="amapManager" :center="center" ref="map" class="amap-demo"> <el-amap-polygon v-for="(polygon, index) in polygons" :vid="index" :ref="`polygon_${index}`" :path="polygon.path" :draggable="polygon.draggable" :events="polygon.events"> </el-amap-polygon> </el-amap> </div> </template> <style> .amap-demo { height: 300px; } </style> <script> let amapManager = new VueAMap.AMapManager(); module.exports = { data() { return { zoom: 15, center: [121.5273285, 31.21515044], amapManager: amapManager, polygons: [ { draggable: true, path: [[121.5273285, 31.21515044], [121.5293285, 31.21515044], [121.5293285, 31.21915044], [121.5273285, 31.21515044]], events: { click: () => { alert('click polygon'); console.log(amapManager.getComponent(0)); // 通过 manager 取到高德 Polygon 实例 console.log(this.$refs.map.$$getCenter()); // 地图当前中心点 console.log(this.$refs.polygon_0[0].$$getPath()); // 多边形边界坐标 } } } ] }; } }; </script>示例中涉及三个关键 API 入口,均可以在仓库源码中逐一定位:
VueAMap.AMapManager:实例覆盖物的注册中心,源码见 amap-manager.js。setComponent(id, component)以vid为键把高德实例存入Map,getComponent(id)反向取出,示例中amapManager.getComponent(0)正是这一能力的直接应用;this.$refs.map.$$getCenter():地图组件的 ref 帮助方法,由 amap.vue 实现,返回[lng, lat]数组;this.$refs.polygon_0[0].$$getPath():多边形自身的 ref 帮助方法,后文第四节详细解析。
使用前需先完成库的安装与初始化。npm 安装方式见 安装文档(npm install vue-amap --save),然后在入口处注册插件:
import VueAMap from 'vue-amap'; Vue.use(VueAMap); VueAMap.initAMapApiLoader({ key: 'YOUR_KEY', plugin: ['AMap.Scale', 'AMap.OverView', 'AMap.ToolBar', 'AMap.MapType', ...], v: '1.4.4' });initAMapApiLoader的完整参数说明(key、plugin、uiVersion、v、protocol 及其默认值)见 初始化文档。一个值得注意的实现细节是:从 lazy-amap-api-loader.js 的_getScriptSrc可以看到,当配置了plugin时,loader 会自动向插件列表追加'Autocomplete', 'PlaceSearch', 'PolyEditor', 'CircleEditor'四个默认插件,PolyEditor正是在此保证可用的——它是多边形"可编辑"能力(editable属性、addnode/adjust/removenode/end事件)的底层依赖,即使你未显式声明它也已默认加载。
组件与地图的衔接机制同样值得了解:el-amap-polygon不直接创建地图,它在挂载后通过父级el-amap的$amap实例工作,并在 register-component.js 的mounted中订阅AMAP_READY_EVENT事件;而地图组件在 amap.vue 的createMap中完成new AMap.Map后会向所有子组件广播该事件,确保 SDK 异步加载完成前子组件不会拿到空地图。
二、静态属性:仅在初始化时生效
文档定义了两类属性,区分标准是"是否支持响应式"。静态属性只能在组件初始化时传入一次,之后修改不会反映到高德实例上:
| 名称 | 类型 | 说明 |
|---|---|---|
| vid | String | 组件的ID,同时作为AMapManager注册实例的键 |
| bubble | Boolean | 是否将覆盖物的鼠标或 touch 等事件冒泡到地图上(自 v1.3 新增),默认值:false |
从 amap-polygon.vue 的props声明看,vid与bubble和其他属性一样都是组件 prop,但"静态"二字的含义体现在框架层面:高德 SDK 对某些配置只接受构造时的参数。bubble正是这类配置——它决定覆盖物事件是否冒泡到地图,影响"点击多边形时地图的 click 事件是否同时触发"这一行为,通常需要在初始化时确定。
三、动态属性:支持响应式
动态属性在运行时修改会实时同步到高德实例。完整清单如下(继承自官方文档,参数说明以文档与高德 JS API 为准):
| 名称 | 类型 | 说明 |
|---|---|---|
| path | Array | 多边形轮廓线的节点坐标数组。当为"环"多边形时(多边形区域在多边形内显示为"岛"),path 为二维数组,数组元素为多边形轮廓的节点坐标数组;"环"多边形时要求数组第一个元素为外多边形,其余为"岛"多边形,外多边形需包含"岛"多边形,否则程序不作处理 |
| visible | Boolean | 是否可见 |
| editable | Boolean | 多边形当前是否可编辑 |
| zIndex | Number | 多边形覆盖物的叠加顺序。地图上存在多个多边形叠加时,使级别较高的在上层显示,默认 zIndex:10 |
| strokeColor | String | 线条颜色,使用 16 进制颜色代码赋值,默认值为 #006600 |
| strokeOpacity | Float | 轮廓线透明度,取值范围 [0,1],0 表示完全透明,1 表示不透明,默认为 0.9 |
| strokeWeight | Number | 轮廓线宽度 |
| fillColor | String | 多边形填充颜色,使用 16 进制颜色代码赋值,如 #FFAA00 |
| fillOpacity | Float | 多边形填充透明度,取值范围 [0,1],0 表示完全透明,1 表示不透明,默认为 0.9 |
| extData | Any | 用户自定义属性,支持 JavaScript API 任意数据类型,如 Polygon 的 id 等 |
| strokeStyle | String | 轮廓线样式,实线:solid,虚线:dashed |
| draggable | Boolean | 设置多边形是否可拖拽移动,默认为 false |
此外,从 amap-polygon.vue 的props声明可以确认,组件实际还接收strokeDasharray、events、onceEvents三个 prop(前者控制虚线段样式,后两者用于声明事件回调,见第五节)。
这些属性是如何做到"响应式"的?答案在 register-component.js 的setPropWatchers中:组件注册完成后会对每个 prop 调用this.$watch,值变化时通过getHandlerFun找到对应的更新函数并调用。getHandlerFun的查找逻辑(第 44-50 行)体现了框架的设计:
- 优先使用组件自定义的
handlers[prop]; - 否则回退到高德实例的
set + 大驼峰属性名方法(如strokeColor→setStrokeColor); - 再否则回退到通用的
setOptions。
以 amap-polygon.vue 的handlers为例,三个属性因无法用简单 setter 表达而做了定制:
handlers: { visible(flag) { flag === false ? this.hide() : this.show(); // 可见性对应 hide()/show() }, zIndex(num) { this.setOptions({ zIndex: num }); // zIndex 走 setOptions }, editable(flag) { flag === true ? this.editor.open() : this.editor.close(); // 编辑状态对应 PolyEditor 开关 } }注意editable的实现直接操作AMap.PolyEditor的open/close,这也解释了前文提到PolyEditor插件为何是默认加载项。另外,initProps(第 147-158 行)说明editable与visible属于"不能在构造选项中生效"的属性,会在注册后额外初始化一次,确保初始值正确。
关于path的坐标格式:示例中传入的是[lng, lat]数组。在初始化时,convertProps(register-component.js 第 52-64 行)会把传入的 prop 数据做类型转换后作为new AMap.Polygon(options)的构造参数;而在取回坐标时,$$getPath会用 convert-helper.js 的lngLatTo把AMap.LngLat对象还原为[lng, lat]数组,保证数据在 Vue 侧始终是纯数组形式,便于响应式 diff。
四、ref 可用方法:无副作用的同步帮助方法
组件通过$refs暴露了一组"无副作用的同步帮助方法",官方文档列出的清单如下(返回类型中的AMap.Polygon、AMap.LngLat、MapsEvent均为高德 JS API 类型):
| 函数 | 返回 | 说明 |
|---|---|---|
| $$getInstance() | AMap.Polygon | 获取 polygon 实例 |
| $$getPath() | [ [lng: Number, lat: Number] ] | 获取 polygon 的边界坐标 |
| $$contains(point) | Boolean | polygon 是否包含某点,参数为 [lng, lat] 或 AMap.LngLat |
| $$getExtData() | any | 获取用户自定义属性 |
源码实现见 amap-polygon.vue 第 51-60 行 及 register-component.js 第 190-192 行:
$$getPath() { return this.$amapComponent.getPath().map(lngLatTo); }, $$getExtData() { return this.$amapComponent.getExtData(); }, $$contains(point) { if (Array.isArray(point)) point = new AMap.LngLat(point[0], point[1]); return this.$amapComponent.getBounds().contains(point); }两点实现层面的说明:
$$contains的实现是委托给getBounds().contains(point),即以多边形的包围盒(矩形边界)判断点是否在内,而非严格的轮廓包含判断。从源码结构看,用它做"粗筛"没问题,若需要精确的轮廓包含判断,可先经它过滤后再自行做点在多边形内的计算;- 组件销毁时的清理逻辑在 register-component.js 的 destroyed 钩子:依次执行
setMap(null)(从地图移除)、close、editor.close()(关闭编辑器)、解绑全部事件监听(unregisterEvents→ event-helper.js 的clearListeners)并撤销所有 prop watcher。这套机制保证了v-if/v-for动态增删多边形时不会残留监听器或覆盖物,是动态列表场景(如示例中的v-for)可靠的基础。
五、事件:普通事件与编辑器事件的双通道绑定
多边形支持的事件完整清单如下:
| 事件 | 参数 | 说明 |
|---|---|---|
| init | Object | 组件初始化完成时触发,参数为高德组件实例 |
| click | MapsEvent | 鼠标左键单击事件 |
| dblclick | MapsEvent | 鼠标左键双击事件 |
| rightclick | MapsEvent | 右键单击 |
| hide | {type, target} | 隐藏 |
| show | {type, target} | 显示 |
| mousedown | MapsEvent | 鼠标按下 |
| mouseup | MapsEvent | 鼠标抬起 |
| mouseover | MapsEvent | 鼠标经过 |
| mouseout | MapsEvent | 鼠标移出 |
| change | — | 属性发生变化时 |
| touchstart | MapsEvent | 触摸开始时触发事件,仅适用移动设备 |
| touchmove | MapsEvent | 触摸移动进行中时触发事件,仅适用移动设备 |
| touchend | MapsEvent | 触摸结束时触发事件,仅适用移动设备 |
| addnode | MapsEvent | 编辑状态下,通过鼠标在折线上增加一个节点或在多边形上增加一个顶点时触发 |
| adjust | MapsEvent | 编辑状态下,鼠标调整折线上某个节点或多边形上某个顶点的位置时触发 |
| removenode | MapsEvent | 编辑状态下,通过鼠标在折线上删除一个节点或在多边形上删除一个顶点时触发 |
| end | {type, target} | 关闭编辑状态时触发,target 即为编辑后的多边形对象 |
这些事件的注册机制分为两条通道,理解它们可以解释"为什么编辑器事件要写在同一个events对象里就能生效":
- 普通事件通道:register-component.js 的 registerEvents 遍历
eventsprop,用 event-helper.js 的addListener(底层是AMap.event.addListener)逐个绑定到$amapComponent;onceEventsprop 则走addListenerOnce。eventsprop 本身也是响应式的——setPropWatchers中对prop === 'events'做了特判,变化时会先unregisterEvents再registerEvents,实现事件回调的热更新; - 编辑器事件通道:
addnode/adjust/removenode/end/move五个事件在高德侧挂在AMap.PolyEditor实例上而非多边形实例上,因此 editor-component.js 的 setEditorEvents 会从events中过滤出这些事件名,单独绑定到this.$amapComponent.editor。编辑器实例在组件初始化时创建:amap-polygon.vue 第 49 行this.$amapComponent.editor = new AMap.PolyEditor(this.$amap, this.$amapComponent)。
init事件的触发点在 register-component.js 的 registerRest:实例创建、事件绑定、属性初始化、watcher 设置、manager 注册全部完成后,若用户定义了events.init,则以(instance, map, manager)三个参数回调——这是你在 Vue 侧拿到原生高德实例的安全时机。编辑结果落地的典型写法是监听end事件,从e.target.getPath()取回编辑后的节点数组(注意此时节点是AMap.LngLat对象,通常需.map(p => [p.lng, p.lat])转回数组)。
六、进阶实践要点小结
综合文档与源码,落地多边形覆盖物时建议把握以下要点:
- 初始化顺序:
el-amap内部通过 SDK 加载 Promise +AMAP_READY_EVENT广播保证子覆盖物晚于地图创建(见 amap.vue 第 209-224 行),无需手动处理时序; - 属性分层:
vid、bubble等静态属性只在初始化生效;path、颜色、透明度、zIndex、draggable、visible、editable均支持响应式修改,修改 Vue data 即同步到地图; - 取数与交互:统一用
$refs帮助方法($$getInstance、$$getPath、$$contains、$$getExtData)或AMapManager.getComponent(vid)获取实例,避免直接触达内部状态; - 编辑场景:依赖默认加载的
PolyEditor插件,通过editable开关编辑状态,用addnode/adjust/removenode/end事件跟踪编辑过程; - 动态增删:
v-for场景下组件销毁时会自动setMap(null)、关闭编辑器并清理监听器,可以放心增删列表项。
仓库中多边形组件、注册 mixin、编辑器 mixin 与管理器的完整源码分别在 amap-polygon.vue、register-component.js、editor-component.js 与 amap-manager.js,相关地图组件的初始化行为可通过 amap.spec.js 中的实例创建与AMapManager事件用例进一步验证。
- 前端
- UI组件
- GIS
【免费下载链接】vue-amap
🌍 基于 Vue 2.x 和高德地图的地图组件
相关推荐
vue-amap 圆形覆盖物组件 el-amap-circle 完全解析:属性、事件与源码实现
vue amap 圆形覆盖物组件 el amap circle 完全解析:属性、事件与源码实现 本文基于 vue amap 仓库中 圆形组件文档 https:/
前端UI组件GISvue-amap 椭圆覆盖物 el-amap-ellipse 实战:从基础示例到属性、事件与响应式实现的源码级解析
vue amap 椭圆覆盖物 el amap ellipse 实战:从基础示例到属性、事件与响应式实现的源码级解析 本文以 vue amap 官方文档中的椭圆覆
前端UI组件GISvue-amap 图片覆盖物实战指南:el-amap-ground-image 的 bounds 配置、属性响应式与事件处理
vue amap 图片覆盖物实战指南:el amap ground image 的 bounds 配置、属性响应式与事件处理 本篇基于 vue amap(基于
前端UI组件GIS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考