Delphi 老兵用 TMS WEB Core 写 Web:环境搭建、组件模型与前后端通信实战
简介这份PDF教程面向希望用Delphi切入Web前端开发的初学者与进阶开发者围绕TMS WEB Core框架讲解如何以Delphi或Lazarus快速构建网站、Web应用及跨Windows、Mac、iOS、Android、Linux的App。内容从Delphi/Object Pascal的历史与现状讲起对比IntraWEB、uniGUI与TMS WEB Core三款Web框架的特点再深入配置TMS WEB Core环境、项目设置与自动化版本管理并覆盖Pas2JS编译器、RTL运行时库、预处理器、命令行编译、页面设计与调试等关键环节帮助传统Delphi程序员理解100%纯HTML/JS应用的开发思路。资源为单个PDF文件压缩包约3.84MB已有5000余人学习。目录结构清晰涵盖框架简介、快速入门、组件技能与部署分发等模块适合作为系统学习TMS WEB Core、查漏补缺的参考读物。1. 当 Delphi 老兵开始写 WebTMS WEB Core 到底解决了什么一个做了十几年 Delphi 桌面端的人第一次被要求「把现有系统搬到浏览器里」大概率会经历三个阶段先想用 uniGUI 或 IntraWeb 糊一个再想干脆重写成 Vue 后端 API最后发现两条路都要把积累多年的业务逻辑推倒重来。TMS WEB Core 出现的意义恰恰是给这批人第三条路——用 Object Pascal 写前端编译成 JavaScript在浏览器里跑同时保留 Delphi 的 IDE、调试器和 VCL 式的组件思维。它不是把 Delphi 变成 Web 框架而是把 Web 前端变成 Delphi 能编译的目标平台。这篇文章面向的是有 Delphi 基础、想低成本切入 Web 交付的一线开发者从环境搭建、组件模型、前后端通信到部署排错把这条链路走通一遍。2. 环境搭建与第一个可运行页面从 IDE 到浏览器2.1 安装 TMS WEB Core 与编译器链路TMS WEB Core 的安装包通过 TMS 官方的订阅渠道获取安装时会向 Delphi IDE 注册一套新的工程类型和一组组件面板页。安装完成后在 Delphi 的File New Other里能看到TMS WEB Core分类里面包含TMS Web Application、TMS Web Core Web Application等模板。这里有个容易忽略的点TMS WEB Core 依赖一个 Pascal-to-JavaScript 的编译器pas2js它随安装包一起部署但需要确认 IDE 的库路径里已经包含TMSWEBCore的源码目录否则编译时会报找不到WEBLib.Controls之类的单元。安装后建议先做一次环境自检确认编译器可用# 在 Delphi 安装目录下查找 pas2js 编译器可执行文件 # 常见路径形如 # C:\Program Files (x86)\Embarcadero\Studio\版本\TMSWeb\Compiler\pas2js.exe # 用 --version 确认编译器能独立运行 pas2js.exe --version这段命令的作用是确认 pas2js 编译器本身没有损坏。如果这一步就报错后面所有编译问题都不用查了直接重装 TMS WEB Core。参数上没什么可调的--version只是探活。真正需要关注的是 IDE 里Tools Options TMS WEB下的编译器路径配置如果团队里多人协作建议把这个路径写进项目组的统一环境说明避免有人用旧版本编译器产出不一致的 JS。2.2 用 TMS Web Application 模板跑通最小页面新建TMS Web Application后IDE 会生成一个包含Project1.html、Project1.dpr和主窗体单元的结构。主窗体的类型是TWebForm上面可以放TWebButton、TWebEdit、TWebLabel这类组件。写一个最小交互按钮点击后把输入框内容回显到标签上。// Unit1.pas procedure TForm1.WebButton1Click(Sender: TObject); begin // WebEdit1.Text 在浏览器端就是 input 的 value WebLabel1.Caption : 你输入的是 WebEdit1.Text; end;这段代码的逻辑很直白但背后发生的事值得说清楚WebButton1Click并不是在服务端执行的它被 pas2js 编译成 JavaScript 事件回调直接绑定到浏览器 DOM 上。WebEdit1.Text读写的是真实 DOM 节点的 value 属性WebLabel1.Caption最终落到 innerHTML。也就是说你写的是 Pascal跑的是前端。参数层面TWebEdit的Text属性是双向的但要注意它默认不触发OnChange的实时同步如果需要输入即响应得用OnKeyUp或开启TWebEdit的ImmediateUpdate类属性不同版本命名略有差异以组件面板实际属性为准。编译运行后IDE 会启动一个内置的轻量 Web 服务器把生成的 HTML、JS、CSS 托管在本地端口浏览器自动打开。这个内置服务器只用于开发调试不要拿它当生产部署方案。2.3 工程结构里哪些文件该进版本库一个 TMS WEB Core 工程编译后会产出大量中间文件如果全丢进 Git仓库会迅速膨胀。常见做法是只保留源码和配置文件/目录是否入库说明*.dpr/*.pas是工程与单元源码*.html是页面宿主文件含 JS 引用*.dproj是工程配置含编译选项TMSWeb\输出目录否编译产物含大量 JS*.js.map否调试映射按需生成.identcache/.dsk否IDE 本地状态这张表的价值在于避免团队协作时有人把编译产物提交上去导致每次拉取都产生冲突。我一般会在.gitignore里直接写死输出目录名而不是逐个文件排除。3. 组件模型与页面布局TWebForm 和 VCL 的差异在哪3.1 TWebForm 不是 TForm别用桌面思维套从 VCL 转过来的人最容易翻车的地方是把TWebForm当成TForm用。两者在生命周期上有本质区别VCL 的窗体是操作系统窗口TWebForm最终是一个div容器它的Show、Hide、Close对应的是 DOM 的显示隐藏和路由跳转。更关键的是TWebForm没有真正的「模态」概念ShowModal在 Web 端要么被模拟成遮罩层要么直接不可用取决于你用的组件版本。布局上VCL 的绝对坐标Left/Top在 Web 端会变成 CSS 的 absolute 定位一旦浏览器窗口尺寸变化页面就会错位。正确做法是优先使用TWebPanel配合Align属性或者用TWebResponsiveGrid这类响应式容器。我见过一个项目主界面全部用绝对坐标摆控件在开发机上看着没问题用户用笔记本一打开右侧按钮全跑到屏幕外这就是典型的桌面思维残留。3.2 用 TWebResponsiveGrid 做自适应布局的最小示例下面这段代码演示如何用响应式网格把三个卡片横向排列窄屏时自动换行// 在 FormCreate 里动态构建网格内容 procedure TForm1.WebFormCreate(Sender: TObject); var i: Integer; Card: TWebPanel; begin WebResponsiveGrid1.Columns : 3; // 宽屏三列 WebResponsiveGrid1.Breakpoint : 768; // 小于 768px 时降为单列 for i : 1 to 3 do begin Card : TWebPanel.Create(Self); Card.Parent : WebResponsiveGrid1; Card.ElementClassName : card; // 挂自定义 CSS 类 Card.Caption : 卡片 IntToStr(i); end; end;逻辑说明Columns控制宽屏下的列数Breakpoint是触发降列的像素阈值这两个参数决定了布局的响应行为。ElementClassName是关键它把 Delphi 组件和外部 CSS 类关联起来样式细节交给 CSS 文件去写而不是在 Pascal 里硬编码颜色和边距。参数调整上Breakpoint要根据目标用户的主流设备来定如果用户大量使用平板768 可能偏小可以调到 1024。失败时先看浏览器开发者工具里网格容器的实际宽度和 CSS 类是否生效很多时候是 CSS 文件没被正确引用。3.3 组件事件在浏览器端的真实执行时机TWebButton.OnClick、TWebEdit.OnChange这些事件编译后都是标准的 DOM 事件监听。这意味着它们的执行时机和浏览器事件模型完全一致OnClick在 mouseup 之后触发OnChange在 input 失焦或回车时触发。如果你在OnChange里做实时校验用户输入过程中不会触发体验上会觉得「没反应」。这时候应该改用OnKeyUp或OnInput如果组件暴露了的话。另一个坑是事件里的异常处理。在 VCL 里未捕获异常会弹出一个对话框在浏览器里未捕获异常只会静默写进 console用户看到的是「点了没反应」。所以每个事件处理里最好包一层 try-except把错误信息通过console.error或页面提示暴露出来否则排查起来就是黑匣子。4. 前后端通信TMS WEB Core 怎么和 Delphi 后端对接4.1 三种通信方式的选型对比TMS WEB Core 前端和 Delphi 后端之间常见有三条路REST/JSON、WebSocket、以及 TMS 自家的 RemoteDB。选型取决于数据实时性和团队技术栈。方式适用场景实时性实现复杂度REST/JSON常规增删改查请求-响应低WebSocket消息推送、协同编辑双向实时中RemoteDB直接操作数据集准实时中高大多数业务系统用 REST 就够了。RemoteDB 适合那种「前端要直接翻数据集」的场景但它对网络稳定性和权限控制要求更高不适合公网弱网环境。4.2 用 TWebHttpRequest 调 REST 接口的完整写法假设后端有一个 Delphi 写的 REST 服务返回 JSON 格式的用户列表。前端这样调procedure TForm1.LoadUsers; var Req: TWebHttpRequest; begin Req : TWebHttpRequest.Create(Self); Req.URL : https://your-api-host/api/users; Req.Command : httpGET; Req.Headers.Add(Authorization: Bearer FToken); Req.OnResponse : HandleUsersResponse; Req.Execute; end; procedure TForm1.HandleUsersResponse(Sender: TObject; const AResponse: string); var Arr: TJSArray; i: Integer; Obj: TJSObject; begin // AResponse 是原始 JSON 字符串用 TJSJSON 解析 Arr : TJSJSON.parse(AResponse) as TJSArray; for i : 0 to Arr.Length - 1 do begin Obj : Arr[i] as TJSObject; // 把数据填进 TWebResponsiveGrid 或表格组件 AddUserRow(Obj[name], Obj[email]); end; end;逻辑说明TWebHttpRequest是异步的Execute发出请求后不阻塞结果在OnResponse回调里处理。Command指定 HTTP 方法Headers用来带认证信息。解析部分用的是TJSJSON这是 pas2js 提供的 JS 互操作单元TJSArray和TJSObject直接映射到 JavaScript 的数组和对象。参数上URL建议从配置读取而不是硬编码Authorization头的 token 要处理过期刷新否则用户会莫名其妙被登出。失败排查顺序先看浏览器 Network 面板里请求是否发出、状态码是多少如果是 401查 token如果是 0 或 CORS 错误查后端是否允许了前端域名。CORS 是 Delphi 后端最容易漏配的一环需要在响应头里加Access-Control-Allow-Origin。4.3 后端 Delphi 侧返回 JSON 的注意事项后端如果用TWebModule或TIdHTTPServer手写 REST返回 JSON 时要注意字符编码。Delphi 字符串默认是 UTF-16直接写进响应流可能变成乱码。常见做法是用TJSONObject构造后ToJSON再按 UTF-8 编码写出。另外日期字段建议统一用 ISO 8601 字符串不要用 Delphi 的TDateTime浮点数直接序列化前端解析会疯掉。5. 避坑与常见问题那些让我加班到凌晨的细节5.1 编译通过但页面白屏现象IDE 里编译零错误浏览器打开一片空白console 里可能只有一行Uncaught SyntaxError。原因通常是某个单元的initialization段里访问了浏览器不存在的对象或者 HTML 宿主文件里 JS 引用路径写错。解决先看 console 第一条错误定位到具体 JS 文件再检查Project1.html里script标签的 src 是否指向了正确的输出目录。我一般会在 HTML 里加一个window.onerror钩子把错误直接显示在页面上省得每次开 console。5.2 中文乱码现象页面上的中文变成问号或方块。原因HTML 文件缺少meta charsetutf-8或者后端返回的 Content-Type 没带 charset。解决在 HTML 的 head 里显式声明 UTF-8后端响应头加Content-Type: application/json; charsetutf-8。Delphi 侧写字符串时确认用的是 UTF-8 编码流。5.3 事件绑定失效现象按钮点了没反应但代码逻辑没问题。原因组件在FormCreate之前就被创建或者动态创建的组件没有正确设置Parent。解决动态组件一定要先Create再设Parent最后挂事件顺序错了DOM 节点还没插入文档事件监听就绑不上。5.4 内存泄漏与组件销毁现象页面长时间运行后越来越卡。原因动态创建的TWebPanel、TWebHttpRequest没有在不用时Free。浏览器端虽然没有传统内存泄漏那么严重但 DOM 节点和 JS 对象堆积一样会拖慢页面。解决对一次性使用的请求对象在OnResponse末尾Free对动态 UI切换视图时显式清理旧节点。5.5 部署后接口 404现象本地开发一切正常部署到服务器后所有 API 请求 404。原因开发时用的是 IDE 内置服务器加相对路径部署后前端静态资源和后端 API 不在同一域名或路径下。解决把 API 基地址抽成配置项部署时按环境注入后端确认路由前缀和前端请求路径一致。这个问题没有玄学就是路径对不上但每次换环境都要重新确认一遍。6. 进阶把调试和构建流程固化下来走到这里基本链路已经通了。但要让这个方案在团队里真正跑起来还得解决两件事调试效率和构建一致性。调试方面TMS WEB Core 支持生成 source map浏览器开发者工具里能直接看到 Pascal 源码行号。开启方式是在工程选项里勾选生成 map 文件部署时把.js.map一起放上去生产环境可以关掉。我习惯在开发阶段始终开着 source map断点直接打在 Pascal 代码上比看编译后的 JS 舒服太多。如果遇到 source map 不生效先确认浏览器是否启用了「Enable JavaScript source maps」再看 map 文件里的 sources 路径是否和实际文件结构匹配。构建一致性方面pas2js 编译器版本、TMS WEB Core 组件版本、Delphi IDE 版本三者要锁死。我吃过一次亏本地用新版本编译器构建通过CI 机器上还是旧版本产出的 JS 在某个浏览器上行为不一致排查了一整天才定位到编译器差异。现在的做法是在项目根目录放一个build-env.md写清楚三个版本号CI 脚本里加一步版本校验不匹配直接失败。还有一个值得固化的习惯把常用的页面交互封装成可复用的TWebForm基类或辅助单元。比如统一的错误提示、统一的 loading 遮罩、统一的 token 刷新逻辑。这些在 VCL 时代就是基类干的事搬到 Web 端一样适用。不要每个页面都重写一遍TWebHttpRequest的创建和销毁那是给自己挖坑。最后说一个验证方法每次改完前端逻辑不要只在 IDE 内置浏览器里测至少再用一个真实浏览器Chrome 或 Edge的隐私模式跑一遍。内置浏览器和真实浏览器在缓存、CORS、安全策略上都有差异很多问题只有真实环境才暴露。这个习惯帮我省下了至少三次「上线后才发现」的尴尬。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Matlab电场仿真入门:线电荷离散化与可视化三部曲

Matlab电场仿真入门:线电荷离散化与可视化三部曲

简介:本资源是一份面向电子信息、物理电子及电磁场相关专业本科生的Matlab仿真实验报告,聚焦线电荷电场与电位分布的数值建模与可视化。通过库仑定律、电场强度定义及势函数积分原理,结合Matlab矩阵运算、网格生成(meshgrid&#…

2026/10/16 0:13:12 阅读更多 →
京东2020首页高仿:CSS布局、滚动动效与性能优化实战

京东2020首页高仿:CSS布局、滚动动效与性能优化实战

1. 项目概述:这不是“抄界面”,而是一次前端布局与动效的系统性复盘“高仿京东2020版首页布局及刷新效果”——这个标题乍看像学生作业,实则藏着前端工程师日常攻坚中最硬核的三重关卡:结构语义化落地能力、响应式断点控制精度、以…

2026/10/16 0:13:12 阅读更多 →
SAS数据步行列变换:宽表转长表与混合类型处理实战

SAS数据步行列变换:宽表转长表与混合类型处理实战

1. 项目概述:为什么“行列变换”是SAS数据步里最常被低估的硬功夫?在某高校统计实验室带学生做课程设计时,我见过太多人把SAS当成“高级Excel”来用——导入数据、跑个proc means、画张直方图,就以为掌握了。直到某次模拟项目X中&…

2026/10/16 0:13:12 阅读更多 →

最新新闻

仓颉 ArkUI Counter 计数器组件完全指南:增减计数、按钮控制与事件绑定

仓颉 ArkUI Counter 计数器组件完全指南:增减计数、按钮控制与事件绑定

文档知识库教程OpenHarmony 【免费下载链接】CangjieCorpus 本仓库为仓颉编程语言语料库,聚焦 仓颉编程语言 核心知识体系,整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源,经结构化处理与专业标注,构建为支持 R…

2026/10/16 2:03:46 阅读更多 →
如何让多个git worktree并行开发零端口冲突?Sonar port: auto与${port}变量详解

如何让多个git worktree并行开发零端口冲突?Sonar port: auto与${port}变量详解

【免费下载链接】sonar CLI tool for inspecting and managing services listening on localhost ports 项目地址: https://gitcode.com/gh_mirrors/sonar17/sonar 点击查看 免费下载 Sonar 是一款本地端口管理与服务启动 CLI 工具,它用 port: auto 自动…

2026/10/16 2:03:46 阅读更多 →
仓颉鸿蒙 Location Kit 位置服务错误码全解:从 3301000 到 3301800 的成因分析与处理指南

仓颉鸿蒙 Location Kit 位置服务错误码全解:从 3301000 到 3301800 的成因分析与处理指南

文档知识库教程OpenHarmony 【免费下载链接】CangjieCorpus 本仓库为仓颉编程语言语料库,聚焦 仓颉编程语言 核心知识体系,整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源,经结构化处理与专业标注,构建为支持 R…

2026/10/16 2:03:46 阅读更多 →
10分钟上手 Modly:从安装到首次生成本地 3D 模型

10分钟上手 Modly:从安装到首次生成本地 3D 模型

10分钟上手 Modly:从安装到首次生成本地 3D 模型 【免费下载链接】modly Desktop app to generate 3D models from images or prompt using local AI — runs entirely on your GPU 项目地址: https://gitcode.com/GitHub_Trending/mo/modly Modly 是一款本地…

2026/10/16 2:03:46 阅读更多 →
非线性最小二乘优化实战:高斯-牛顿、LM与Dog-Leg方法详解

非线性最小二乘优化实战:高斯-牛顿、LM与Dog-Leg方法详解

1. 为什么非线性最小二乘值得单独整理如果你做过视觉SLAM、点云配准、曲线拟合、相机标定,或者任何需要"让模型输出逼近真实观测"的工程任务,那你大概率已经和非线性最小二乘打过照面了。它要解决的问题非常朴素:给定一组观测数据和…

2026/10/16 2:03:46 阅读更多 →
四轮把模糊想法逼成明确决策:grill-me 实战指南

四轮把模糊想法逼成明确决策:grill-me 实战指南

四轮把模糊想法逼成明确决策:grill-me 实战指南 【免费下载链接】skills Skills for Real Engineers. Straight from my .agents directory. 项目地址: https://gitcode.com/GitHub_Trending/skills13/skills 你把一个没想清楚的主意丢给编码 agent&#xff…

2026/10/16 2:02:46 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →