Angular中Esri Maps PopupTemplate调用及图层获取问题咨询
嘿,这个问题我之前在做Angular集成Esri地图的时候也踩过坑,刚好能给你一些实用的解决方案😎
一、强制弹窗每次都执行Content方法
Esri的Popup默认会偷偷缓存已经渲染过的要素内容,所以切换回已查看的要素时,它就懒得再跑一遍content回调了。你可以用这两种方式绕开这个缓存:
1. 监听要素切换,手动重置弹窗内容
每次选中新要素(包括重复的)时,主动清除弹窗的缓存并重新渲染:
mapView.popup.watch('selectedFeature', (graphic: __esri.Graphic) => { // 先清掉现有缓存内容 mapView.popup.clearContent(); // 重新调用content函数生成新内容 const template = mapView.popup.popupTemplate; if (template && typeof template.content === 'function') { const newContent = template.content({ graphic }); mapView.popup.content = newContent; } // 这里后续再结合图层获取逻辑处理数据发布 });
不过这种方式可能会有一点点闪烁,毕竟是先清再渲染。
2. 每次都创建新的Angular组件实例(推荐)
别复用之前的组件nativeElement,每次触发content时都新建一个组件实例——这样Popup的缓存机制就没用武之地了:
// 给子图层设置PopupTemplate的时候这么写 layer.popupTemplate = new PopupTemplate({ content: (feature: { graphic: __esri.Graphic }) => { // 每次都创建全新的PopupComponent实例 const componentFactory = this.componentFactoryResolver.resolveComponentFactory(PopupComponent); const componentRef = componentFactory.create(this.injector); // 发布数据到组件 this.publishPopupData(layer, feature.graphic.attributes); componentRef.instance.popupData = /* 把处理好的模型传进去 */; componentRef.changeDetectorRef.detectChanges(); return componentRef.location.nativeElement; } });
这样不管用户怎么切要素,哪怕来回切同一个,都会重新执行content,生成新组件,完美避开缓存问题。
二、获取MapImageLayer子图层的引用
MapImageLayer的子图层返回的Graphic确实经常不带layer引用(毕竟是从服务端返回的,不是客户端直接创建的),但有两个靠谱的办法拿到所属子图层:
1. 用Graphic的layerId找子图层
服务端返回的Graphic会带有layerId属性,对应子图层的ID,你可以通过MapImageLayer的findLayerById方法拿到子图层:
// 先拿到你的MapImageLayer实例 const mapImageLayer = this.map.findLayerById('your-map-image-layer-id') as __esri.MapImageLayer; mapView.popup.watch('selectedFeature', (graphic: __esri.Graphic) => { if (graphic?.layerId) { const targetSubLayer = mapImageLayer.findLayerById(graphic.layerId); if (targetSubLayer) { this.publishPopupData(targetSubLayer, graphic.attributes); } } });
2. 初始化时把图层引用绑到闭包里(更稳妥)
当初始化MapImageLayer的子图层时,直接在PopupTemplate的content函数里把当前子图层的引用“存”起来,后续用的时候直接拿:
// 遍历MapImageLayer的所有子图层 mapImageLayer.allLayers.forEach(subLayer => { subLayer.popupTemplate = new PopupTemplate({ content: (feature: { graphic: __esri.Graphic }) => { // 这里直接用闭包里的subLayer,绝对不会错 this.publishPopupData(subLayer, feature.graphic.attributes); // 同样推荐每次创建新组件实例 const componentFactory = this.componentFactoryResolver.resolveComponentFactory(PopupComponent); const componentRef = componentFactory.create(this.injector); componentRef.instance.popupData = /* 你的模型数据 */; componentRef.changeDetectorRef.detectChanges(); return componentRef.location.nativeElement; } }); });
这种方式完全不需要依赖Graphic的任何属性,初始化时就绑定了正确的子图层,最靠谱。
综合最优方案
把上面的两种方法结合起来:初始化子图层时绑定图层引用,同时每次创建新组件实例。这样既解决了缓存不触发content的问题,又能100%拿到正确的子图层,完美适配你的场景。
内容的提问来源于stack exchange,提问作者asgallant

