基于 Delphi 的前后端分离:之四,使用 HTMX 让页面元素组件化

Delphi 最厉害的地方就是 Delphi 的可视化控件。在设计期可以拖拉控件设计界面,运行期也可以动态创建控件并且用程序决定控件摆放在界面的哪个位置,如何摆放。

对于 HTML5 的页面,使用 HTMX 就可以很容易把各路开源的页面代码,组件化,实现模块化开发,简化代码,方便维护。

以下是一个简单的例子

需求:

我想在页面上,放一个图表。这个图表不是写死在页面代码里面的,而是作为一个独立组件,在页面打开以后,当用户点击了一个按钮以后,才动态呈现出来。

额外说明:如果这个功能可以实现,那就可以让页面定时去刷新这个图表。

说明:图表代码来自:Beautiful HTML5 Charts & Graphs | 10x Fast | Simple API (canvasjs.com)

对于 Delphi 程序员来说,漂亮的 HTML5 页面图表的代码多半不会写,没关系,我们去找成熟的开源代码,把它封装一下变成 Delphi 的控件!

实现方法:

页面代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Delphi & HTMX Demo</title>
    <script src="https://unpkg.com/htmx.org@1.9.12"></script> 
	<script src="https://cdn.canvasjs.com/canvasjs.min.js"> </script>

  </head>
  <body>
    <h1 id="header">Delphi & HTMX Rocks!</h1>
    
	<div>
	<button hx-get="/MyChart" hx-target="#Chart1" hx-swap="innerHTML">Show Chart</button>
	</div>
	<p></p>
	<div>
	  这里显示图表 Show Chart Here
	  <span id="Chart1"></span>
	</div>
	
	<div id="chartContainer" style="height: 370px; width: 100%;"></div>

  </body>
</html>
页面代码解释:

这个页面有一个按钮,按钮里面有 HTMX 的相关代码,当用户点下这个按钮,会去访问服务器的“/MyChart” 这个路径,并将服务器返回的内容,写到 id="Chart1" 那个 span 里面去。

id=“chartContainer” 的这个 DIV,则是图表的容器。页面打开后,什么也没有,仅仅是预先留一个容器。

上述页面从 WEB 服务器打开后,浏览器仅仅显示一个按钮,和“这里显示图表”的那一行文字。

当用户点击按钮后,图表才从服务器发送给页面,然后图表才显示出来。

Delphi 的代码:

在 Delphi IDE 里面,创建一个 Stand alone 的 WebBroker 工程,保存。运行它,Delphi 自动在该工程的目录底下创建了 Win32/Debug/  这个目录。编译好的 EXE 程序就在这个目录里面。

把 index.html 页面文件拷贝到这个目录底下。

把图表的代码文件拷贝到这个目录底下。图表的代码文件我命名为 MyChart.txt。

以下是 MyChart.txt 的内容:

<script type="text/javascript">

var chart = new CanvasJS.Chart("chartContainer", {
	theme: "light1", // "light2", "dark1", "dark2"
	animationEnabled: false, // change to true		
	title:{
		text: "Basic Column Chart"
	},
	data: [
	{
		// Change type to "bar", "area", "spline", "pie",etc.
		type: "column",
		dataPoints: [
			{ label: "apple",  y: 10  },
			{ label: "orange", y: 15  },
			{ label: "banana", y: 25  },
			{ label: "mango",  y: 30  },
			{ label: "grape",  y: 28  }
		]
	}
	]
});
chart.render();

</script>

我们可以把 MyChart.txt 看作是一个图表控件。

在 Delphi 工程里面,打开 WebModule1 这个模块,双击其界面,弹出一个窗口,是编辑 Web Action 的界面。这个窗口里面一定有一个 Action,就是 Default 的 Action。在这个窗口里面,鼠标右键菜单,选择"Add",增加一个 Action。然后选中这个 Action,在左侧属性面板里面,给这个 Action 的 PathInfo 属性,填入【MyChart】。然后在属性面板上切换页标签到事件面板,这里只有一个事件【OnAction】,双击,Delphi 自动帮我们创建这个事件的代码框架。

Delphi 的 WebBroker 框架的简介:

WebBroker 框架,核心就是这个 WebModule1 里面,由程序员添加的多个不同的 Action,每个 Action 对应一个 PathInfo,这个 PathInfo 对应 WEB 访问的 URL 的路径。比如:

1. http://127.0.0.1:8080 就是访问我自己本机这个 Delphi 程序作为一个 Web 服务器。这时候在 Delphi 的代码里面,就是触发那个默认的(Default)的 Action。也就是 URL 的根目录。

2. http://127.0.0.1:8080/MyChart 也是访问到这个 Web Server,但会触发到前面说的那个 PathInfo 为 【MyChart】的 Action 的 OnAction 事件代码。

有了这个概念,我们就知道,浏览器访问 WEB SERVER 的不同路径,对应 Delphi 的不同事件方法。当然,在这个事件方法中,我们还可以通过 Request 这个变量,读到页面传递过来的信息,比如,在 URL 的路径底下的参数,类似:

http://127.0.0.1:8080/MyChart?MyNo=25&MyId=pcplayer

那么,在 OnAction 事件方法里面,可以通过 Request 这个对象,读到 MyNo 和 MyId 的值,因此服务器可以根据这些参数,输出动态的内容。

本例子 Delphi 的代码:
unit WebModuleUnit1;

interface

uses
  System.SysUtils, System.Classes, Web.HTTPApp;

type
  TWebModule1 = class(TWebModule)
    procedure WebModule1DefaultHandlerAction(Sender: TObject;
      Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
    procedure WebModule1WebActionItem1Action(Sender: TObject;
      Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  WebModuleClass: TComponentClass = TWebModule1;

implementation

uses System.IOUtils;

{%CLASSGROUP 'Vcl.Controls.TControl'}

{$R *.dfm}

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  Response.Content := UTF8Decode(TFile.ReadAllText('index.html'));
end;

procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  Response.Content := UTF8Decode(TFile.ReadAllText('MyChart.txt'));
end;

end.
上述代码解释:

1. 当浏览器地址栏输入 http://127.0.0.1:8080 访问本服务器,触发 WebModule1DefaultHandlerAction 这个事件方法。在这里,我把 index.html 的内容发送给浏览器。这里就是浏览器从 Web Server 直接打开页面。加上 UTF8Decode 是因为这个页面文件是用 UTF8 编码保存的。

2. 当用户在浏览器点下按钮,触发 HTMX 访问服务器的 /MyChart 这个路径,在作为服务器的 Delphi 程序,则触发了 PathInfo 为 MyChart 的这个 Action 的事件方法。在这里,我把图表的内容发送给浏览器。图表内容就是前面提到的 MyChart.txt。在这里,图表就作为一个单独的文件,并没有写入服务器端的 Delphi 的代码里面,也没有写入页面文件 index.html 里面。这样就实现了组件化,可以使用在多个不同的页面的多个不同的位置,需要图表的地方,而无需重复写图表代码到页面代码里面,也无需重复写图表代码到 Delphi 的代码里面。

这就是组件化的目的:

1. 同一段代码,重复使用;

2. 封装,方便修改。当需要修改图表时,仅仅需要修改 MyChat.txt 这个文件,而不是整个项目到处都需要修改。

3. 封装,方便 debug。假设图表有问题,也仅仅需要针对 MyChart.txt 里面的代码进行测试和修改。

如何让图表动态

上述测试程序,加载的 MyChart.txt 这个图表的代码里面,图表的数据是写死在这个代码里面的。

实际应用的时候,图表的数据是动态变化的。

其实非常简单,可以在 Delphi 里面,写一个方法,这个方法是加载 MyChart.txt 然后根据输入的数据,去修改 MyChart.txt 里面有关数据的部分。这些数据是 JSON 格式,Delphi 是可以直接输出 JSON 格式的数据的。我们只要把 Delphi 生成的数据,直接替换掉 MyChart.txt 里面的数据,再输出给页面就可以实现图表的动态变化。这部分功能,甚至可以封装为一个单独的 Delphi 控件!

这样一来,用 Delphi 开发 Web 程序,对于前端,我们也可以组件化,用控件来实现了。而且,这样做非常简单。

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值