为什么我的Angular子组件的加载Spinner始终无法显示?
Angular地图组件加载Spinner不显示问题解决方案
问题根因
创建Marker、动态Leaflet tooltip组件的逻辑为同步阻塞执行,全程占用浏览器主线程。Angular初始化app-route子组件时,loading初始值为true,但主线程被耗时逻辑占满,没有空闲时间将该状态渲染到DOM;直到所有同步逻辑执行完成、loading被设为false后,浏览器才会一次性渲染最终的表格视图,因此加载Spinner从未展示。
解决方案
基础方案
使用setTimeout将耗时逻辑推入宏任务队列,等待当前变更检测周期完成、Spinner渲染完成后再执行同步逻辑,即使延迟设为0也可以生效:
ngOnInit(): void { // 等待首次视图渲染完成后再执行耗时逻辑 setTimeout(() => { const factory = this.resolver.resolveComponentFactory(LeafletTooltipComponent); for(let routePoint of this.route.points) { let marker = new L.CircleMarker([routePoint.lat, routePoint.lng],{}); let tooltip = new L.Tooltip(); let component = factory.create(this.injector); component.instance.routePoint= routePoint; component.changeDetectorRef.detectChanges(); let tooltipContent = component.location.nativeElement; tooltip.setContent(tooltipContent); marker.bindTooltip(tooltip); this.markers.addLayer(marker); } this.loading = false; }, 0) }
大数量场景优化(可选)
如果路线点数量过多、循环耗时较长,可以配合Angular的NgZone将非UI变更逻辑放到Angular变更检测区域外执行,减少不必要的变更检测开销,进一步降低卡顿:
import { NgZone } from '@angular/core'; // 构造器注入NgZone constructor(private ngZone: NgZone) {} ngOnInit(): void { setTimeout(() => { // 非UI逻辑放到Angular区域外执行,不触发额外变更检测 this.ngZone.runOutsideAngular(() => { const factory = this.resolver.resolveComponentFactory(LeafletTooltipComponent); for(let routePoint of this.route.points) { let marker = new L.CircleMarker([routePoint.lat, routePoint.lng],{}); let tooltip = new L.Tooltip(); let component = factory.create(this.injector); component.instance.routePoint= routePoint; component.changeDetectorRef.detectChanges(); let tooltipContent = component.location.nativeElement; tooltip.setContent(tooltipContent); marker.bindTooltip(tooltip); this.markers.addLayer(marker); } }); // 执行完成后更新加载状态,触发UI变更 this.loading = false; }, 0); }
内容的提问来源于stack exchange,提问作者Lapskaus
相关产品推荐
相关产品推荐

