Flask+HTMX场景下首次跳转页面Bokeh图表无法加载问题
这种现象主要由以下几个核心原因导致:
HTMX默认不执行动态加载内容中的脚本
当通过HTMX从index.html加载home.html片段时,HTMX默认不会自动执行新加载内容里的<script>代码。Bokeh图表必须运行初始化脚本(比如Bokeh.embed.embed_item())才能完成渲染,首次加载时这段脚本没被触发,所以图表无法显示。后续跳转时,要么之前的脚本已经在全局环境中执行过,要么浏览器缓存了必要的Bokeh资源,因此能正常渲染。Bokeh资源加载与脚本执行时机不匹配
如果home.html中的Bokeh JS/CSS是随页面片段一起引入的,首次请求时这些资源还没下载完成,初始化脚本就已经尝试执行,导致找不到全局的Bokeh对象,渲染失败。后续请求时浏览器已经缓存了这些资源,加载速度更快,脚本能顺利找到依赖并执行。DOM初始化事件未触发
Bokeh的初始化代码通常绑定在DOMContentLoaded事件上,但HTMX加载的是页面片段,此时整个页面的DOM早已加载完成,这个事件不会再次触发,导致首次加载时初始化代码没被调用。
对应解决方案
强制HTMX执行动态脚本
不要依赖页面的DOM加载事件,直接在home.html的脚本中执行初始化逻辑,或者通过HTMX的事件回调触发。比如:// 直接执行初始化,不等待DOMContentLoaded if (typeof Bokeh !== 'undefined') { Bokeh.embed.embed_item(your_plot_config); } else { // 若Bokeh还未加载,先加载资源再初始化 const bokehScript = document.createElement('script'); bokehScript.src = "https://cdn.bokeh.org/bokeh/release/bokeh-3.3.2.min.js"; bokehScript.onload = () => Bokeh.embed.embed_item(your_plot_config); document.head.appendChild(bokehScript); }提前在index.html加载Bokeh资源
在index.html的<head>中预先引入Bokeh的CSS和JS,这样首次加载home.html时,资源已经存在于浏览器中:<link rel="stylesheet" href="https://cdn.bokeh.org/bokeh/release/bokeh-3.3.2.min.css"> <script src="https://cdn.bokeh.org/bokeh/release/bokeh-3.3.2.min.js"></script>利用HTMX的后置事件触发初始化
在触发跳转的HTMX按钮上添加事件回调,确保页面片段加载完成后执行Bokeh初始化:<button hx-get="/home" hx-target="#content" hx-on::after-swap="initBokeh()">跳转到Home</button>然后在全局JS中定义初始化函数:
function initBokeh() { Bokeh.embed.embed_item(your_plot_config); }
内容的提问来源于stack exchange,提问作者btgorman

