Vue3 + 高德地图:实现多功能标记点管理与事件交互
概述
在现代前端GIS应用开发中,地图标记点(Marker)的管理是核心功能之一。本文将详细介绍如何基于Vue3、Ant Design Vue 4.0和高德地图API,实现一个高度可配置、支持多类型标记点、具备丰富交互功能的标记点管理系统。
技术栈
-
Vue3:使用Composition API进行逻辑封装
-
JavaScript:主要开发语言
-
Ant Design Vue 4.0:UI组件库
-
高德地图API:地图展示与交互基础
-
事件总线:组件间通信机制
核心功能设计
1. 标记点类型配置系统
首先,我们创建一个中央化的配置系统来管理不同类型的标记点:
// marker-config.js
import { markerEnum } from "@/utils/enum";
export const markerConfigs = {
[markerEnum.SXJ]: {
key: markerEnum.SXJ,
idKey: "id", // 唯一标识字段
textKey: "name", // 文本标签字段
isOnLine: (data) => true, // 在线状态检测
iconFilter: (data, isHover) => {
let image = null;
image = isHover ? sxjHoverMarker : sxjMarker;
return getMarkerIcon(image);
},
zIndex: 35, // 图层层级
},
[markerEnum.ZBJL]: {
key: markerEnum.ZBJL,
isOnLine: (data) => true,
iconFilter: (data, isHover = false) => {
let image = null;
image = isHover ? zbjlHoverMarker : zbjlMarker;
return getMarkerIcon(image);
},
idKey: "id",
textKey: "license",
zIndex: 35,
},
// 其他标记点类型...
};
// 获取配置的辅助函数
export const getMarkerConfig = (type) => markerConfigs[type];
2. 自定义Hook封装
使用Vue3的Composition API封装标记点管理逻辑:
// useMarker.js
export default () => {
let textLabel = null;
const markerTypes = ref([]);
const markers = ref([]);
const selectMarkerId = ref(null);
// 创建单个标记点
const createMarker = (point) => {
if (!useMap.AMap) return;
const config = getMarkerConfig(point.type);
if (!config) return message.info("未找到对应标点配置");
// 生成唯一标识符
const uuid = `${config.key}:${point[config.idKey]}`;
const position = new AMap.LngLat(point.longitude, point.latitude);
// 创建高德地图Marker实例
const marker = new AMap.Marker({
map: useMap.AMap,
position,
anchor: "bottom-center",
zIndex: config.zIndex,
extData: { item: { ...point, uuid }, data: config },
});
// 初始图标设置
updateMarkerIcon(marker, config, selectMarkerId.value === uuid);
// 事件绑定
if (config.isOnLine(point)) {
bindMarkerEvents(marker, config);
} else {
marker.setCursor("default");
}
return marker;
};
return { setMarkers, clearMarkers };
};
3. 交互事件绑定
实现丰富的鼠标交互效果:
const bindMarkerEvents = (marker, config) => {
const point = marker.getExtData();
const uuid = point.item?.uuid;
// 鼠标移入事件
marker.on("mouseover", () => {
marker.setTop(true); // 置顶显示
if (selectMarkerId.value !== uuid) {
updateMarkerIcon(marker, config, true); // 切换为悬停图标
}
// 显示文本标签
if (config.textKey && textLabel) {
const text = point.item[config.textKey];
const position = marker.getPosition();
textLabel.show();
textLabel.setOffset(new AMap.Pixel(0, -55));
textLabel.setPosition(position);
textLabel.setText(`${text}`);
}
});
// 鼠标移出事件
marker.on("mouseout", () => {
marker.setTop(false);
if (selectMarkerId.value !== uuid) {
updateMarkerIcon(marker, config, false); // 恢复默认图标
}
if (config.textKey && textLabel) {
textLabel.hide(); // 隐藏文本标签
}
});
// 点击事件
marker.on("click", () => {
const prevUUID = selectMarkerId.value;
selectMarkerId.value = uuid;
// 更新前一个选中标记点的状态
if (prevUUID && prevUUID !== uuid) {
const { marker, config } = getPrevMarkerConfig(prevUUID);
if (marker && config) {
updateMarkerIcon(marker, config, false);
}
}
// 更新当前标记点状态
updateMarkerIcon(marker, config, true);
// 计算信息框偏移量
let offset = new AMap.Pixel(0, -55);
if (config.key === markerEnum.CLOSE) {
offset = new AMap.Pixel(0, -25);
}
// 发送事件总线消息
eventBus.emit("marker-click", {
type: point.item?.type,
extData: { ...point, offset },
});
});
};
4. 批量管理与状态控制
提供批量操作接口和状态管理:
// 设置标记点数据
const setMarkers = (points) => {
// 清除旧标点
clearMarkers();
// 创建文本标签实例
textLabel = new AMap.Text({
map: useMap.AMap,
anchor: "bottom-center",
visible: false,
zIndex: 30,
});
// 批量创建新标记点
markers.value = points.map((point) => createMarker(point));
markerTypes.value = [...new Set(points.map((p) => p.type))];
};
// 清除所有标记点
const clearMarkers = () => {
// 通知各类型组件关闭
markerTypes.value.forEach((type) => {
eventBus.emit("marker-close", type);
});
// 从地图移除所有标记点
markers.value.forEach((marker) => {
marker?.setMap(null);
});
// 清理文本标签
textLabel?.setMap(null);
textLabel = null;
markers.value = [];
markerTypes.value = [];
};
// 更新标记点图标
const updateMarkerIcon = (marker, config, isHover = false) => {
const extData = marker.getExtData();
marker.setIcon(config.iconFilter(extData.item, isHover));
};
5. 事件总线集成
通过事件总线实现跨组件通信:
// 监听外部关闭事件
eventBus.on("marker-close", (uuid) => {
if (!uuid.includes("undefined")) {
const { marker, config } = getPrevMarkerConfig(uuid);
if (marker && config) updateMarkerIcon(marker, config, false);
}
});
// 获取前一个标记点配置
const getPrevMarkerConfig = (uuid) => {
const prevMarker = markers.value.find(
(m) => m.getExtData().item?.uuid === uuid
);
const point = prevMarker?.getExtData();
return {
marker: prevMarker,
config: getMarkerConfig(point?.item?.type),
};
};
6. 在组件中使用
关键技术点
1. 配置驱动设计
通过中央化的配置对象,实现了标记点类型的灵活扩展。新增标记点类型只需在配置文件中添加相应配置即可。
2. 响应式状态管理
利用Vue3的ref和watch实现标记点状态的响应式管理,确保UI与数据状态同步。
3. 性能优化
-
使用事件委托减少事件绑定数量
-
按需创建和销毁标记点
-
利用高德地图的Marker层级控制
4. 组件通信
通过自定义事件总线实现标记点与业务组件的解耦通信。
总结
本文介绍了一个基于Vue3和高德地图的完整标记点管理系统。该系统具有以下特点:
-
高度可配置:通过配置文件管理所有标记点类型
-
丰富的交互:支持悬停、点击、选中等多种交互状态
-
良好的性能:优化了标记点的创建、更新和销毁机制
-
可扩展性:便于新增标记点类型和交互行为
-
代码复用:通过自定义Hook实现逻辑复用
这种设计模式不仅适用于地图应用,也可借鉴到其他需要管理大量可视化元素的场景中。通过合理的架构设计,可以使复杂的地图标记点管理变得简单而高效。
💰【我的自研工具推荐】轻松网购返利,技术人的省钱助手
✅ 自用省钱,分享有奖
支持主流电商平台 | 返利透明可提现
👇 微信扫码,立即体验

说明:本工具为我个人独立开发,若您有技术合作或使用疑问,欢迎在博客私信交流。





