如何在Dash应用中为Bootstrap折叠容器内的Leaflet地图调用invalidateSize
Dash Leaflet地图嵌套Bootstrap折叠灰屏解决方案
你遇到的是Leaflet地图尺寸计算时机的典型问题,Bootstrap折叠组件未展开时DOM元素尺寸为0,Leaflet初始化时读取的尺寸错误,展开后没有主动刷新就会出现灰屏。以下是可行实现方案:
实现步骤
你可以通过Dash的客户端回调直接在前端执行JS调用invalidateSize方法,不需要额外引入外部资源,是最便捷的实现方式:
- 从dash导入
clientside_callback用于定义前端执行的回调逻辑 - 新增客户端回调监听折叠组件的
is_open状态,折叠打开时延时调用地图的尺寸刷新方法(加延时是为了等Bootstrap折叠的动画执行完,确保DOM尺寸已经更新)
完整可运行代码
import dash import dash_bootstrap_components as dbc import dash_core_components as dcc import dash_html_components as html import dash_leaflet as dl from dash.dependencies import Input, Output, State # 导入客户端回调 from dash import clientside_callback map_collapse = dbc.Collapse( html.Div( [ dl.Map( [ dl.TileLayer(), dl.LocateControl(options={'locateOptions': {'enableHighAccuracy': True}}) ], id="map", style={'width': '100%', 'height': '50vh', 'margin': "auto", "display": "block"} ) ] ), id="map-collapse", is_open=False, style={ 'width': '800px', 'height': '400px' } ) collapse_button = dbc.Button( "Open collapse", id="collapse-button", className="mb-3", color="primary", n_clicks=0, ) app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) app.layout = html.Div( [ collapse_button, map_collapse ] ) @app.callback( Output("map-collapse", 'is_open'), [Input("collapse-button", "n_clicks")], [State("map-collapse", "is_open")] ) def toggle_collapse(n, is_open): if n: return not is_open # 这里返回False就是初始折叠关闭,返回True是初始打开,按需调整 return False # 新增客户端回调,折叠打开时刷新地图尺寸 clientside_callback( """ function(is_open) { if(is_open) { // 150ms延时匹配Bootstrap折叠的默认动画时长 setTimeout(() => { // 获取Leaflet地图实例 const mapEle = document.getElementById('map'); if(mapEle && mapEle._leaflet_map) { mapEle._leaflet_map.invalidateSize(); } }, 150); } // 不需要修改任何属性,返回无更新 return window.dash_clientside.no_update; } """, # 随便绑定一个地图的属性作为输出,实际不会修改 Output("map", "zoom"), Input("map-collapse", "is_open"), prevent_initial_call=True ) if __name__ == '__main__': app.title = 'Dash App' app.run_server(debug=True)
补充说明
如果你的dash-leaflet版本比较旧,获取地图实例的方式可以换成window.dl_map.getLeafletElement(),效果是一致的。
内容的提问来源于stack exchange,提问作者Jasol
相关产品推荐
相关产品推荐

