发布日期 :2026-09-07 06:57:57 UTC
作者 :xuzhiping
访问量: 10 次浏览
事件绑定直接作用于地图实例或者图层、Marker 对象。 支持地图全局事件,也支持单个要素独立事件;事件监听可以指定回调函数,提供对应的解绑方法。 事件对象内部可以直接拿到经纬度、屏幕像素坐标等信息。 图层销毁时,必须手动移除绑定事件,否则会产生内存残留。
事件系统采用事件订阅模式,使用addEventListener进行监听,监听后返回回调 ID,取消监听必须使用这个 ID。 地图本身、实体 Entity、数据源 DataSource 都可以注册事件。 鼠标交互不直接绑定到要素,更多通过屏幕拾取 API,根据屏幕坐标反向获取地理实体。 Cesium 对内存泄漏十分敏感,事件不解绑会持续占用 GPU 与内存,页面长时间运行性能会持续下降。
事件绑定挂载在 map 地图实例上,区分地图事件和图层事件。 图层事件需要指定图层 ID,只有点击该图层内的要素才会触发回调。 可以从事件参数拿到 feature 要素对象,直接读取 GeoJSON 属性。 移除事件使用off()方法,传入事件名称与回调函数。
通用开发提示:Vue、React 组件销毁时,务必要清除所有地图事件监听,组件反复挂载卸载会造成事件重复注册,出现点击一次回调执行多次的 bug。
地图全局鼠标事件,获取点击经纬度:
// 地图点击事件
map.on('click', (e) => {
// e.latlng 获取地理坐标
const {lat,lng} = e.latlng;
console.log('点击坐标:', lat, lng);
});
// 鼠标悬浮移动
map.on('mousemove', (e) => {
const {lat,lng} = e.latlng;
});
// marker标记点独立点击事件
marker.on('click', (e) => {
console.log('点击标记点');
});
// 解绑事件
map.off('click');
marker.off('click');
Cesium 没有直接给 Entity 绑定 click 事件,依靠 Screen‑SpaceEventHandler 屏幕事件处理器。
// 创建屏幕事件处理器
const handler = new Cesium.ScreenSpaceEventHandler(map.scene.canvas);
// 左键点击事件
handler.setInputAction((event) => {
// 根据屏幕坐标拾取要素
const pick = map.scene.pick(event.position);
if (Cesium.defined(pick)) {
// 获取实体对象
const entity = pick.id;
console.log('拾取到实体', entity);
}
// 获取点击位置经纬度
const cartesian = map.scene.globe.pick(map.camera.getPickRay(event.position), map.scene);
if(cartesian){
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const lon = Cesium.Math.toDegrees(cartographic.longitude);
const lat = Cesium.Math.toDegrees(cartographic.latitude);
console.log(lon,lat);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 销毁事件处理器,必须执行
handler.destroy();
// 地图全局点击
map.on('click', (e)=>{
console.log('经纬度', e.lngLat);
});
// 指定图层要素点击事件,只响应该图层内数据
map.on('click', 'point-layer', (e)=>{
const feature = e.features[0];
console.log('要素属性', feature.properties);
});
// 鼠标悬浮,修改鼠标样式
map.on('mouseenter', 'point-layer', ()=>{
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'point-layer', ()=>{
map.getCanvas().style.cursor = '';
});
// 移除事件
map.off('click','point-layer');
弹窗是高频交互组件,分为两种实现思路。
1.框架内置 Popup 组件:跟随地图坐标,地图缩放拖拽自动跟随位置;
2.DOM 自定义弹窗:Vue/React 组件渲染 DOM,根据地理坐标实时换算屏幕像素,手动控制显示隐藏。
业务建议:简单场景直接使用框架自带 Popup;弹窗内部需要复杂表单、表格、业务组件,优先采用自定义 DOM 弹窗方案。
const popupContent = `<div>点位信息<br/>名称:测试点位</div>`;
const popup = L.popup().setContent(popupContent).setLatLng([30,120]);
map.openPopup(popup);
Cesium 原生没有 Popup 组件,主流方案:监听地图渲染更新,将经纬度实时转为屏幕坐标,控制 DOM 弹窗位置。
// 经纬度转屏幕坐标
const position = Cesium.Cartesian3.fromDegrees(120,30);
const screenPos = Cesium.SceneTransforms.wgs84ToWindowCoordinates(map.scene, position);
if(screenPos){
// 设置弹窗dom left top
}
new mapboxgl.Popup()
.setLngLat([120,30])
.setHTML('<div>弹窗内容</div>')
.addTo(map);
监听地图缩放、平移、旋转,获取当前地图状态。
zoomend、moveend事件,地图缩放、拖拽结束触发camera.changed,相机发生任意变化就触发,回调频率很高,建议做节流处理zoomend、moveend事件注意:
camera.changed触发非常频繁,如果业务逻辑较重,一定要增加节流函数,避免页面卡顿。
1.组件销毁忘记解绑事件
Vue、React 组件销毁,如果没有执行 off、destroy 操作,事件依旧存活,组件重新挂载会重复注册事件,点击一次执行多次回调。
2.Cesium ScreenSpaceEventHandler 忘记 destroy
不销毁会持续监听画布交互,内存持续上涨,页面运行越久越卡。
3.相机高频事件不做节流
相机、move 类事件短时间大量触发,回调内部不要写过重业务逻辑。
4.要素已经移除,事件还保留在要素对象上
删除 Marker、图层时,优先解绑对应要素自身事件。
5.拾取坐标为空判断
地形遮挡、视角问题,pick 拾取有可能返回 undefined,代码必须做判空,否则直接报错。