学习unigui【44】如何和uinHTMLFrame打交道
一个极简、可复用的“UniGUI(M) + HTMLFrame/iframe 通信桥模板”。只保留关键段落:装桥、推数据、收事件、延迟关闭。你以后做水质、PLC、Luckysheet、任何 iframe UI,都按这个骨架套。
0)命名约定(统一协议)
-
前端 → 父页面:
{type:'ui_event', name:'close'|'refresh'|'save', payload:{...}} -
服务器 → 前端:
{type:'ui_render', name:'render', payload:{...}} -
ACK:
{type:'ui_ack', name:'close'}(可选但强烈建议)
A) iframe 页面(xxx.html)— 最小模板
B) Delphi:Frame(承载 HTMLFrame/iframe)— 最小模板
1)核心字段与公开方法(骨架)
2)InitTemplate:注入 iframe + 装桥 + 绑定目标
3)InstallBridgeOnce:父页面监听 postMessage → ajaxRequest
这里最关键:把 iframe 的
{type:'ui_event',name:'close'}转成ajaxRequest(UnimHTMLFrame1,'ui_close',[])
4)BindTarget:目标固定为 UnimHTMLFrame1(最稳)
不玩 JSId/Ext.getCmp 那套。目标就是 UniGUI 组件对象本身(通过 ComponentQuery 找到 UniGUI 的 ajax target)。
你已经验证“目标对象乱找”会出 Object not found,所以这里用 UniGUI 自己的“ajax target”方式绑定——最稳是:直接把 target 存成 UnimHTMLFrame1 的客户端对象引用。在 UniGUI 前端,组件一般都有 UnimHTMLFrame1.JSName 可直接引用;如果你环境里没有,就用 ComponentQuery 通过 UnimHTMLFrame1.JSId 找到 UniGUI 包装对象。
用 JSId 找对象(但找的是 UniGUI 组件,不是随便 Ext 控件):
5)服务器端收事件:绑定到 UnimHTMLFrame1.OnAjaxEvent
6)延迟关闭(避免 session list object not found)
7)推数据给 iframe(RenderToIframe)
C) 你要记住的“5 个硬规则”(像螺丝刀一样随手用)
-
iframe 只负责 UI,不碰 UniGUI:只用 postMessage
-
父页面只干一件事:
message → ajaxRequest -
ajaxRequest 的 target 必须是“UniGUI session 对象”,不能乱拿 Ext id
-
关闭/销毁类动作必须延迟(Timer),避免 session list 报错
-
所有调试先看 ACK 和 bind log:ACK=消息到父;bind=目标存在;两者都对才可能进 Delphi
这个模板你可以直接复制成一个新的 TUniFrame_UiBridge,以后 PLC/水质/报表/编辑器都套它。你要我把它整理成你项目里能直接编译的完整 unit(含 dfm 绑定点、具体 uses、最少依赖)也可以。
更健康的策略(你现在已经走到这条路上了)
-
页面内部交互:局部闭环
事件落点固定在本页面的UnimHTMLFrame(或本 Form),逻辑清晰、可复用、可预测。 -
真正的全局规则:Delphi 端做“服务端真相源”
统一退出、权限校验、状态栏信息、全局状态机——这些都放在服务器端(MainModule/ServerModule/统一服务类),前端只是“显示结果”和“提交请求”。 -
跨模块通讯:用“服务器端事件/状态”而不是“前端广播”
比如:登录状态变化、权限变更、强制退出
→ 服务器端更新状态
→ 当前页面下一次交互/定时心跳/必要时推送时再响应(你也可以做很轻量的轮询或服务器推送,但那是另一套专门机制)
你可以记一个简单原则
前端不要当操作系统。
前端是 UI 和输入层;全局一致性、权限、生命周期这些“系统级规则”,交给 Delphi 端。
这条原则会让你未来做 Luckysheet、ECharts、各种 HTMLFrame 都更稳:每个页面都是一个小闭环,服务器端是唯一权威的大脑。

浙公网安备 33010602011771号