WebView2是越来越香了。 WebView2不但是Win11自带的系统组件,Win10也已经自动推送安装。即使是少量没有安装WebView2的系统使用aardio中的web。view也会自动安装(不需要写任何代码)。 我用WebView2开发了很多项目,不得不说WebView2稳定可靠、性能强悍,接口简洁,是真的让人省心。htmx。js 这里介绍一个适合用于WebView2的极简前端组件htmx。js,这个组件最大的特色就是简单,一学就会,也很容易理解。 我们正常浏览一个网页的过程是在浏览器里输入网址,向HTTP服务器发送请求。然后服务器返回HTML代码,浏览器显示页面。 但是htmx。js脑洞大开,让网页上的每一个HTML节点都可以向服务器发送请求并获取HTML,并实时更新页面上指定的节点。而且不需要写任何JavaScript代码。起步 首先我们打开aardio,创建WebView2工程并选择htmx。js模板: 生成的工程如下: 点运行可直接测试效果,点发布可生成独立EXE文件。 在工程管理器中右键点网页弹出菜单,然后点用外部编辑器打开,如果安装了VSCode会使用VSCode打开网页目录。 在VSCode中点击并打开index。html源码: htmx。js基础 打开index。html,先看最简单的htmx。js示例:buttonhxgetapiindex。aardiohxswapinnerHTMLhxtriggerclickhxtargetinfop点这里发送GET请求button 注意看凡是hx前缀的属性都是用于htmx。js。 hxtrigger用于指定在什么事件发生时触发HTTP请求,例如:hxtriggerclick 表示在click单击事件发生时触发请求。 hxtrigger可使用标准网页事件名,常用事件如下:load网页元素首次加载时触发请求。click单击时触发请求。这是除表单,表单控件之外所有元素的默认事件。change控件值改变时触发请求。input,textarea,select等控件的默认事件。submit提交表单时触发请求。表单的默认事件。keydown按键时触发请求。keyup放开按键时触发请求。mouseenter鼠标进入时触发请求。mouseleave鼠标离开时触发请求。every时间定时触发请求,例如hxtrggerevery1s指定每隔1秒发送一次请求。 事件名后面还可以添加修饰器,例如修饰器once表示只允许触发一次:hxtriggerclickonce 其他事件修饰器:changed只有在元素的值更改时发出请求delay:延时在指定的延时后发出请求,例如hxtrggerloaddelay:1s指定元素加载后延迟1秒发送请求。如果服务端不断地返回相同HTML并替换节点自身,也可以实现轮询的效果(aardio后端可以控制何时停止轮询)。throttle:延时节流,避免在指定时间内重复请求from:CSS选择器监听指定元素上的事件。 下面的HTML使用了多个事件修饰器:inputtypetexthxtriggerkeyupchangeddelay:500mshxpostapiindex。aardio 这表示在按键放开(keyup),文本框的内容发生改变(changed)时触发,并且延时500毫秒再发送请求。 hxget则指定要请求的是哪个后端页面,例如:hxgetapiindex。aardio 表示事件触发时,请求apiindex。aardio这个页面。因为aardio在启动SPA应用时自动指定了后端根目录为web,所以实际请求的是webapiaardio。 而hxswap则指定要将返回的HTML写入到哪里,innerHTML指定是更新网页节点内部HTML,outerHTML指定替换目标网页节点的全部HTML,其他还有afterbegin,beforebegin,beforeend,afterend,none。这些看名字就知道是什么作用,就不解释了。 hxtarget属性用CSS选择器指定要写入的网页节点,例如:hxtargetinfop 指定服务器返回的HTML写入id为infop的节点。如果省略hxtarget属性表示写入目标是当前节点自身。 hxmx。js在更新HTML时,如果发现新旧html中有id相同的元素会进行优化并平滑显示。 看到这里,htmx。js您已经会用了。 虽然htmx。js文档里有更多花式用法,但一般可能用不上。有些事搞太复杂了也不一定是好事。htmx。jsaardio后端 aardio提供了嵌入式HTTP服务器,可以直接使用aardio代码写网页,支持与PHP类似的模板语法。 aardio的模板语法很简单,aardio代码写在lt;??内部,而HTML代码写在lt;??外部就可以了。实际上lt;??外部的代码被转换为了aardio中print函数的参数。 例如服务端有下面的aardio代码:spanabcspanlt;?response。write(123)? 运行后会自动转换为纯aardio代码如下:print(spanabcspan);response。write(123); 在HTTP后端中,print函数实际上就是指向用于向HTTP客户端输出数据的response。write()函数。 在HTTP后端有两个最常用的对象,request对象包含了所有HTTP请求信息,而response对象为HTTP响应对象,用于向客户端发送数据。 打开aardio自带工具库函数文档,点击fastcgi。client的文档可以查看request,response对象的所有属性与方法。aardio中的所有HTTP服务端实现都统一兼容fastcgi。client文档规定的request,response用法。 也可以参考aardio开始页的《aardio网站开发、FastCGI开发入门教程》。至于aardio模板语法,请参考《aardio语法与使用手册aardio语言模板语法》 aardio的模板语法不仅仅可以用于写HTTP后端,也不仅仅是可以用于输出HTML,实际上可以用于生成任何字符串。aardio中的很多功能都支持这种模板语法,例如运行时编译C代码就支持用aardio模板语法生成C代码。另外aardio提供string。loadcode()函数可以直接解析aardio模板并返回字符串。htmx。js指示动画,aardio后端线程 这里要注意,上面范例工程默认导入的HTTP服务器是:wsock。tcp。simpleHttpServer; 这是一个多线程的HTTP服务端,每次被请求执行的aardio代码都是在后台线程中运行。aardio多线程开发要注意的是每个线程都运行在独立的环境,全局变量是相互隔离的,这个限制实际上让aardio的多线程开发更简洁,坑更少,具体请参考aardio自带范例程序aardio语言多线程。 如果改为wsock。tcp。asynHttpServer则是单线程异步的HTTP服务器。 下面我们仍然使用默认的simpleHttpServer。多线程的好处是耗时操作不会卡界面。后端在进行耗时操作时,网页前端通常需要显示一个动画,htmx。js做这事就很简单。 我们只要简单的修改一下前面讲过的网页代码如下:buttonhxgetapiindex。aardiohxindicatorindicator点这里发送GET请求button imgidindicatorclasshtmxindicatorsrca2020imgdataimg。jpgdatasrcimg02。bs178。combknh395ea4a0d44fa3fb。jpg 主要是增加了hxindicator属性,该属性的值用一个CSS选择器指定了发送HTTP请求时要显示的HTML元素,这里指定的是id为indicator的元素。 实际上我们可以自定义这个请求动画的样式,我们打开样式文件index。css添加下面的样式:。htmxindicator{display:none;}。htmxrequest。htmxindicator{display:inline;} 在发送请求时,网页上被设定的指示元素会自动添加CSS类htmxrequest,HTTP请求结束会移除该类。 然后我们打开对应的aardio后端代码webapiindex。aardio,输入以下代码:spanlt;?if(request。methodGET){这是多线程后端,这里等2秒,网页会显示加载动画sleep(2000);response。write(time())}?span 上面的代码的作用是:如果收到GET请求,线程就休眠2秒以模拟耗时操作。然后输出当前时间。 我们运行一下看看效果: 请求参数 htmx。js提交请求的节点如果是一个表单控件,只要指定name属性就会自动以该名字发送请求参数,参数值就是控件的值。 如果提交请求的节点是表单,则HTTP请求参数为表单内所有控件的值。 也可以在节点的hxvals属性中用一个JSON对象指定请求参数,例如网页这样写:buttonhxgetapiindex。aardiohxvals{myVal:值}点这里发送GET请求button aardio后端就可以使用:request。get〔myval〕 取到HTTP请求参数myval的值。 如果使用POST发送请求,例如:buttonhxpostapiindex。aardiohxvals{myVal:值}点这里发送GET请求button 那么aardio后端可以使用request。post〔myval〕 取到HTTP请求参数myval的值。 在aardio后端使用:request。query(myval) 可以取到GET或POST发送的myval参数值。 hxvals还可以通过加上javascript:或者js:前缀后使用JS对象返回请求参数,例如:buttonhxgetapiindex。aardiohxvalsjavascript:{myVal:值}点这里发送GET请求buttonweb。form也玩htmx。js 有趣的是web。form也可以支持htmx。js。 web。form是基于系统自带的IE内核控件,注意系统虽然删除了IE浏览器,但IE控件属于系统组件,Windows有说明该控件不会被移除。IE控件的好处是从XP到Win11所有操作系统都自带。 而且IE控件很轻量,与本地程序交互的接口也非常方便。Win10,Win11自带的是IE11内核,写写一般的网页还是很好用的。至于Win7因为只有极低的份额,一般软件不用考虑。 htmx。js最后一个支持IE11的版本是1。6。1,这个足够用了。前面说过我们需要的只是局部请求刷新的功能,其他功能我们用不上,所以追新无意义。 首先我们打开aardio工程向导,选择Web界面WebForm然后创建工程即可,新版工程模板默认就是使用htmx。js。 其他HTML代码写法与前面介绍的WebView2基本一样。不过web。form本就支持EXE内嵌资源文件,所以默认并不会启动HTTP服务器,需要多写几句代码。 打开工程的webPage。aardio源码: 可以看到源码中是如下启动HTTP服务器的:importweb。form;varwbweb。form(winform);多线程后端importwsock。tcp。simpleHttpServer;wsock。tcp。simpleHttpServer。documentBasewebvarindexUrlwsock。tcp。simpleHttpServer。startUrl(index。html)wb。go(indexUrl); 我并没有把这几句代码封装到wb。go()函数中。 有些新手总以为代码越少越好,其实并非如此,有时候多写几句更容易看清楚代码的思路,更容易理解我们正在使用的技术。 下面我们看下web。formhtmx。js范例的运行效果: 上面示例程序的主窗口是使用win。ui。tabs做的,只有其中一个标签页用到了网页。 其实一般桌面软件的界面并不是一定要全部使用网页实现。有时候我们将界面中适合用网页呈现的部分用网页做,可能会更好。 我们在使用任何技术时,都要考虑一下适不适合。没有一样技术能适合做所有的事,多个选择总是好事。