Pyodide(PyScript)结合JS加载URL图片无法在HTML页面显示问题
问题成因
图片无法正常显示是4个问题叠加导致的:
- 执行时序不匹配:页面内的原生JS脚本会在浏览器解析到对应位置时立刻执行,但PyScript是异步加载、异步运行Python代码的,JS执行时Python逻辑还没跑完,
img_str变量还未生成,赋值操作拿到的是空值。 - 变量作用域不匹配:
<py-script>块内定义的变量默认是块级局部变量,不会自动挂载到pyodide.globals全局对象上,JS侧根本无法访问到这个变量。 - HTML结构不规范:用于展示图片的文本块、img容器、赋值脚本都写在了
</body>闭合标签外侧,属于无效HTML结构,浏览器解析时会出现不可预期的行为。 - 输出逻辑冲突:你给
<py-script>标签设置了output="image"属性,PyScript会默认把块内生成的matplotlib图表自动渲染到对应容器中,和你手动转base64赋值的逻辑互相干扰,导致渲染异常。
修复方案
- 移除
<py-script>标签上多余的output="image"属性,关闭默认自动输出逻辑,避免和手动渲染流程冲突。 - 直接在Python代码中引入浏览器DOM API完成图片赋值,不需要额外编写原生JS块,从根源上避免跨语言传值的作用域问题、时序问题。
- 修正HTML结构,把所有页面元素、脚本都移动到
<body>标签内部,符合HTML语法规范。 - 可选优化:绘制图片时关闭matplotlib的坐标轴,调整保存图片的边距,去掉多余的空白区域,展示效果更好。
修复后可直接运行的完整代码
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" /> <script defer src="https://pyscript.net/alpha/pyscript.js"></script> <py-env> - matplotlib - imageio </py-env> </head> <body> <h1>PyScript - 从API加载图片展示</h1> <div> <p> 本页面从cataas获取猫咪图片并展示在下方。 </p> </div> <div id="textfield">matplotlib生成的图片:</div> <div id="pyplotdiv"><img id="pyplotfigure"/></div> <py-script> from pyodide.http import pyfetch from io import BytesIO import matplotlib.pyplot as plt import imageio.v3 as iio import io, base64 # 直接引入浏览器document对象,在Python侧操作DOM from js import document # 拉取远程图片 response = await pyfetch(url="https://cataas.com/cat", method="GET") img = iio.imread(BytesIO(await response.bytes()), index=None) # 绘制图片,关闭坐标轴消除多余UI plt.imshow(img) plt.axis('off') # 将图表转换为base64编码的PNG格式 buf = io.BytesIO() plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0) buf.seek(0) img_str = 'data:image/png;base64,' + base64.b64encode(buf.read()).decode('UTF-8') # 直接给img标签的src属性赋值 document.getElementById("pyplotfigure").src = img_str </py-script> </body> </html>
如果你一定要保留JS侧赋值的实现方式,需要做两处修改:一是在Python代码中显式把变量挂载到JS全局作用域,添加
from js import window; window.img_str = img_str;二是把JS赋值逻辑改为监听PyScript执行完成事件后再运行,避免提前执行。这种实现链路更长,容易出问题,不推荐使用。
内容的提问来源于stack exchange,提问作者Vikas Kumar Ojha
相关产品推荐
相关产品推荐

