首页 / Leaflet / API 文档
Evented
先看结论
Leaflet 所有事件能力的基类:地图、图层、控件都从它继承,也可以拿它给普通对象加事件。
L.Evented.extend(props) → Evented 子类
直接实例化也可以:var bus = new L.Evented();。事件回调收到的对象至少有 type 与 target。
方法
| 方法 | 返回 | 说明 |
|---|---|---|
on(types, fn, context?) | this | 绑定事件,多个类型用空格分隔 |
off(types?, fn?, context?) | this | 解绑;不传参数时清掉全部监听 |
once(types, fn, context?) | this | 只触发一次,触发后自动解绑 |
fire(type, data?, propagate?) | this | 触发事件;propagate 为真时向事件父级冒泡 |
listens(type, propagate?) | boolean | 是否有该类型的监听器 |
addEventParent(obj) | this | 设置事件父级,事件可向上冒泡 |
removeEventParent(obj) | this | 移除事件父级 |
addEventListener / removeEventListener | this | on 与 off 的别名 |
给普通对象加事件
var Selection = L.Evented.extend({
select: function (id) {
this.selectedId = id;
this.fire('select', { id: id });
}
});
var selection = new Selection();
selection.on('select', function (e) {
console.log('选中', e.id, '来自', e.target === selection);
});
selection.once('select', function () {
console.log('只执行一次');
});
selection.select(12);
selection.select(13);
e.target 指向触发者,e.type 是事件名。
同一类型上的多个监听器按注册顺序依次执行,一个监听器抛错会影响后面的监听器,
回调里需要容错时自己包一层 try。
事件冒泡
图层默认把自己的事件冒泡给地图,map.on('click', fn) 因此能收到要素上的点击。
自定义对象要冒泡,先把目标设为事件父级:
var layerBus = new L.Evented();
layerBus.addEventParent(map);
layerBus.fire('status', { ready: true }, true);
map.on('status', function (e) {
console.log('收到子级事件', e.ready);
});
fire 的第三个参数不传时不会冒泡。
地图内部的交互事件由 L.Map 自己派发,不依赖这条路径。
解绑要带上函数引用
off('select') 会移除该类型上的全部监听。
只想撤掉自己注册的那一个时,把同一个函数引用传进去:
off('select', handler)。
匿名函数没有引用,注册之后就再也无法单独解绑,组件卸载时容易留下闭包引用。
与 DOM 事件的区别
| 对比项 | L.Evented | 原生 DOM 事件 |
|---|---|---|
| 事件对象 | 普通对象,含 type、target、自定义字段 | MouseEvent 等原生对象 |
| 坐标 | 图层事件带 latlng、layerPoint、containerPoint | 只有 clientX / clientY |
| 冒泡 | 显式 addEventParent 后才会向上 | 沿 DOM 树自动冒泡 |
| 绑定工具 | on / off | L.DomEvent.on / off |
off() 不带参数会清空全部监听。
在组件卸载时这很方便,但如果对象与他人共享(例如全局事件总线),
会把别人的监听一并删掉。共享对象上始终按类型解绑。
经纬志(2026)。《Evented》。https://www.jingweizhi.com/leaflet/api/evented.html(访问日期 2026-11-03)。