> **本文回答**：事件主题总览 —— vjmap `map.on/off` + vjmapext `eventBus.on/off`，覆盖视图 / 交互 / 生命周期 / 实体 / 命令。

# 事件主题 (vjmap + vjmapext)

两套事件体系：

| 来源 | 对象 | 用法 | 主要事件 |
|---|---|---|---|
| vjmap（底座） | `map.on(type, handler)` | 底座原生事件，一个 canvas 的所有鼠标 / 视图 / 生命周期 | `click / move / zoom / load / styledata / render ...` |
| vjmapext（扩展） | `mapcadLayer.eventBus.on(event, handler)` | 针对 CAD 实体 / 命令 / 输入 / 选集 | `entity:added / command:started / selection:changed ...` |

## 子项索引

| 文件 | 主题 |
|---|---|
| [map-interaction](map-interaction.md) | `click / mousemove / dblclick / wheel / contextmenu ...` |
| [map-lifecycle](map-lifecycle.md) | `load / idle / sourcedata / styledata / render / error` |
| [map-view](map-view.md) | `move / moveend / zoom / rotate / pitch` |
| [layer-events](layer-events.md) | `map.on('click', layerId, handler)` 图层级绑定 |
| [bus-entity](../../../vjmapext/references/event/bus-entity.md) | `entity:added / deleted / modified / click / dblclick / mouseenter / mouseleave` |
| [bus-selection](../../../vjmapext/references/event/bus-selection.md) | `selection:changed / boxselect:started / boxselect:ended` |
| [bus-command-mode](../../../vjmapext/references/event/bus-command-mode.md) | `command:started / ended / mode:changed / input:started / ended` |
| [bus-render-store](../../../vjmapext/references/event/bus-render-store.md) | `undo:performed / redo:performed`（`store:changed` / `render:requested` 枚举有定义但 1.0.1 未发射） |
| [cleanup](cleanup.md) | `off / once / clear` 生命周期管理 |

## 最小代码

```js
// vjmap 原生
map.on('click', e => console.log('点到：', e.lngLat));
map.on('click', 'my-layer', e => console.log('点到图层：', e.features[0]));

// vjmapext 事件总线
const { VjmapextEvents } = vjmapext;
mapcadLayer.eventBus.on(VjmapextEvents.EntityAdded, ({ entity }) => {
  console.log('新增实体：', entity.id, entity.type);
});

mapcadLayer.eventBus.on(VjmapextEvents.SelectionChanged, ({ selectedIds }) => {
  console.log('当前选中全集：', selectedIds);   // 全集快照，无增量字段
});

mapcadLayer.eventBus.on(VjmapextEvents.CommandStarted, ({ name }) => {
  console.log('开始命令：', name);
});
```

## 用哪一套？

- 要**地图层面**的事件（click / zoom / contextmenu / 图层要素 hover）→ **map.on**
- 要**实体 / 命令 / 选集**的事件 → **mapcadLayer.eventBus**
- 一般场景两套都用，**各自订阅各自的**，不要互相触发。

## 主题级 Top 5 陷阱

1. **没 `off` 导致泄漏**：组件卸载时要逐一 off，或用 `eventBus.clear()` 一把梭。
2. **匿名函数无法 off**：保存 handler 引用再 off；或用 `once`。
3. **`entity:modified` 里又 modify**：无限循环；用 `styleOnly` 标志或事务分组。
4. **`map.on('click', ...)` 和 `map.on('click', 'layer', ...)` 同时触发**：按注册顺序执行；MapMouseEvent 没有 stopPropagation，`e.preventDefault()` 也拦不住其它监听——在全局 handler 里用 `queryRenderedFeatures(e.point, { layers })` 自查命中后跳过（见 [layer-events §六](layer-events.md#六事件触发顺序)）。
5. **命令执行中鼠标事件干扰命令输入流**：命令期间忽略自定义鼠标处理或判断 `mapcadLayer.commandRegistry.isCommandActive`。

## 相关主题

- map.on 列表 → [map-interaction](map-interaction.md)
- 命令生命周期 → [drawing/execute-command](../../../vjmapext/references/drawing/execute-command.md)
- 实体增删改 → [entity/lifecycle](../../../vjmapext/references/entity/lifecycle.md)
