sgcHTML:无需编写 JavaScript,在 Delphi 中构建现代 Web UI

· 组件

Delphi 开发者已经构建企业应用程序长达三十年。后端部分非常稳固:数据库访问、业务逻辑、报表生成、服务集成。问题始终出在前端。一旦客户要求提供基于浏览器的界面,经典的 Delphi 方式就会陷入困境。你要么选择 IntraWeb(功能强大,但有状态且日渐老化),要么尝试 TMS WEB Core(将 Pascal 编译为 JavaScript,但强制采用客户端部署模型),要么将前端交给 JavaScript 团队并维护两套完全独立的代码库。

sgcHTML 采用了一种不同的方式。它是一个包含 60 余个服务端组件的库,可直接从 Delphi、C++ Builder 或 .NET 代码生成 Bootstrap 5 HTML。你通过属性进行配置,读取 HTML 属性,然后将结果输出。交互性由 htmx 提供,这是一个小型 JavaScript 库,可让服务器根据点击和表单提交来替换页面片段 — 无需你自己编写任何 JavaScript。最终结果是一个完全用 Object Pascal 或 C# 构建的现代、响应式 Web 应用程序。

sgcHTML 解决的问题

标准的 Delphi VCL 架构假设运行的是胖客户端:在 Windows 上运行的窗体、表格和对话框。这种模式对内部工具效果良好。但当客户需要一个可从任何设备浏览器访问的门户,或者 IT 策略禁止安装桌面应用程序时,这种模式就会失效。

sgcHTML 出现之前的替代方案都存在摩擦:

sgcHTML 填补了这一空白:一个原生 Delphi 组件库,其输出是任何浏览器都能理解的标准现代 Bootstrap 5 HTML,由 htmx 保持活跃,全部由单一的 Pascal 或 C# 代码库控制。

工作原理

该架构分为三层。

第一层是组件,例如 TsgcHTMLComponent_ChartTsgcHTMLComponent_DataTableTsgcHTMLComponent_StatCard,它们知道如何将自身描述为 Bootstrap 5 HTML。你通过普通的已发布属性进行配置,调用其 HTML 属性即可获得标记。

第二层是页面构建器TsgcHTMLPageBuilder),它将组件组装成响应式网格。你为每个组件分配 SectionSectionTitleSectionOrderColumnWidth(Bootstrap 的 1–12 列网格)。页面构建器会自动排列它们。

第三层是服务器引擎TsgcHTMLEngine_Server),它将一切连接到来自 sgcWebSockets 的 TsgcWSHTTPServer。请求到达你的 OnCommandGet 处理程序,你用由组件构建的完整 HTML 页面进行响应。Bootstrap CSS 和 JavaScript 作为嵌入资源存储在库内部,因此无需在二进制文件旁边部署任何额外文件。

uses
  sgcWebSocket_Server, sgcHTML_Engine_Server,
  sgcHTML_Template_Bootstrap, sgcHTML_Page,
  sgcHTML_Component_StatCard, sgcHTML_Component_Chart;

var
  oServer:   TsgcWSHTTPServer;
  oEngine:   TsgcHTMLEngine_Server;
  oTemplate: TsgcHTMLTemplate_Bootstrap;
  oPage:     TsgcHTMLPage;
  oStat:     TsgcHTMLComponent_StatCard;
  oChart:    TsgcHTMLComponent_Chart;
begin
  oServer := TsgcWSHTTPServer.Create(nil);
  oServer.Port := 8080;

  oEngine   := TsgcHTMLEngine_Server.Create(nil);
  oEngine.Server := oServer;

  oTemplate := TsgcHTMLTemplate_Bootstrap.Create(nil);
  oTemplate.Title := 'My Dashboard';

  oPage := TsgcHTMLPage.Create(nil);

  // KPI card: total revenue
  oStat := TsgcHTMLComponent_StatCard.Create(nil);
  oStat.PageBuilder := oPage.PageBuilder;
  oStat.Section := 'kpi';
  oStat.SectionOrder := 1;
  oStat.ColumnWidth := cw3;
  oStat.Title := 'Total Revenue';
  oStat.Value := '$128,450';
  oStat.Trend := stUp;
  oStat.TrendValue := '+12%';

  // Revenue trend chart
  oChart := TsgcHTMLComponent_Chart.Create(nil);
  oChart.PageBuilder := oPage.PageBuilder;
  oChart.Section := 'charts';
  oChart.SectionOrder := 1;
  oChart.ColumnWidth := cw8;
  oChart.ChartType := ctLine;
  oChart.Title := 'Monthly Revenue';
  oChart.AddLabel('Jan'); oChart.AddLabel('Feb'); oChart.AddLabel('Mar');
  oChart.AddDataset('2026', [42000, 58000, 64000], '#0d6efd', '', True);

  oServer.Active := True;
end;

60 余个现成组件

sgcHTML 附带了涵盖最常见 Web UI 模式的丰富组件面板。每个组件都是标准的 Delphi 类,你可以拖放到窗体上或在代码中创建:

DataSource 绑定

每个 sgcHTML 组件都支持 DataSource 属性,可将其链接到应用程序中的任意 TDataSource。设置 DataAutoRefresh := True,组件会在底层数据集发生变化时自动重新渲染。若需要更精细的控制,可直接调用 LoadFromDataSet

uses
  sgcHTML_Component_DataTable;

// Populate a data table from a FireDAC query
oTable := TsgcHTMLComponent_DataTable.Create(nil);
oTable.PageBuilder := oPage.PageBuilder;
oTable.Section := 'invoices';
oTable.Title := 'Recent Invoices';
oTable.ShowSearch := True;
oTable.ShowExport := True;
oTable.LoadFromDataSet(FDQuery1, 20); // 20 rows per page

图表组件具有匹配的 LoadFromDataSet 方法,接受标签字段名称和一个或多个值字段名称,因此一个按月收入的查询只需三行代码即可变为柱状图:

oChart.LoadFromDataSet(fdqRevenue, 'month', ['revenue', 'cost']);

通过 htmx 实现交互性 — 无需 JavaScript

静态 HTML 有其用处,但交互式 HTML 才是必需的。sgcHTML 通过 htmx 实现交互性:这是一个小型库(gzip 压缩后 14 KB),可拦截点击和表单提交,向服务器发送 HTTP 请求,并将响应的 HTML 替换到页面中。你的 Delphi OnCommandGetOnCommandOther 处理程序接收请求,重新构建相关组件并返回其 HTML。无需页面刷新,无需 JavaScript 框架。

// Server-side handler: update the chart fragment when the user changes the date range
procedure TMyServer.HandleChartFragment(aReq: TIdHTTPRequestInfo;
  aResp: TIdHTTPResponseInfo);
var
  oChart: TsgcHTMLComponent_Chart;
  vRange: string;
begin
  vRange := aReq.Params.Values['range']; // 'week', 'month', 'year'
  oChart := TsgcHTMLComponent_Chart.Create(nil);
  try
    oChart.ChartType := ctBar;
    LoadRevenueData(oChart, vRange); // your data-loading procedure
    aResp.ContentText := oChart.HTML;
    aResp.ContentType := 'text/html';
  finally
    oChart.Free;
  end;
end;

浏览器中的图表带有一个 hx-get 属性,指向片段端点。当用户在下拉菜单中选择不同的时间范围时,htmx 会就地替换图表 div — 周围的页面不会重新加载。

通过 WebSocket 实现实时更新

由于 sgcHTML 构建在 sgcWebSockets 之上,实时推送是一等功能。当新数据到达 — 新订单、价格跳动、传感器读数 — 你的服务器通过 WebSocket 推送一个 HTML 片段,htmx 将其插入到正确的 DOM 元素中。客户端订阅一个 WebSocket 端点,服务器调用 SendMessage。无需轮询,无需长轮询,无需外部消息代理。

// Push an updated stat card to all connected clients
procedure TDashboardServer.PushRevenueUpdate(aNewRevenue: Double);
var
  oCard: TsgcHTMLComponent_StatCard;
begin
  oCard := TsgcHTMLComponent_StatCard.Create(nil);
  try
    oCard.CardID := 'kpi-revenue';
    oCard.Title := 'Total Revenue';
    oCard.Value := FormatCurr('$#,##0', aNewRevenue);
    oCard.Trend := stUp;
    // Send the HTML fragment to all clients subscribed to this channel
    FWSServer.Broadcast(oCard.HTML);
  finally
    oCard.Free;
  end;
end;

无 JavaScript 构建链,无 npm,无 Node.js

sgcHTML 所需的每个 JavaScript 和 CSS 资源(Bootstrap 5、Chart.js、htmx)均作为二进制资源嵌入在编译后的 Delphi 可执行文件中。你的部署就是单个 .exe 文件。没有 node_modules 目录,没有 webpack 配置,没有 Babel 流程,也没有前端包管理器与后端之间的版本冲突。你只需将 sgcHTML 作为 Delphi 包安装,编译,然后发布。

快速入门

sgcHTML 作为 sgcWebSockets Enterprise 和 All-Access 版本的一部分提供,也可单独购买。免费试用版可供下载。试用版包含全部 60 余个组件,在试用期内不限制任何功能。

该库支持 Delphi 10.2 Tokyo 到 Delphi 13 以及 C++ Builder 10.2 到 13,.NET 版本目标为 .NET 6 及更高版本。所有付费层级均包含完整源代码。

有疑问或售前咨询?联系我们。你将直接收到编写这些代码的人的回复。