強大 WebView2 + 不用寫 JavaScript 的 htmx.js快速開發桌面程式

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 模板:

強大 WebView2 + 不用寫 JavaScript 的 htmx.js快速開發桌面程式

生成的工程如下:

強大 WebView2 + 不用寫 JavaScript 的 htmx.js快速開發桌面程式

點『執行』可直接測試效果,點『釋出』可生成獨立 EXE 檔案 。

在工程管理器中右鍵點『網頁』彈出選單,然後點『用外部編輯器開啟』,如果安裝了 VS Code 會使用 VS Code 開啟網頁目錄。

在 VS Code 中點選並開啟 index。html 原始碼:

強大 WebView2 + 不用寫 JavaScript 的 htmx.js快速開發桌面程式

htmx。js 基礎

開啟 index。html ,先看最簡單的 htmx。js 示例:

<

button

hx-get

=

/api/index。aardio

hx-swap

=

innerHTML

hx-trigger

=

click

hx-target

=

#info-div

>

點這裡傳送 GET 請求

button

>

<

br

>

<

div

id

=

info-div

>

div

>

注意看凡是 “hx-” 字首的屬性都是用於 htmx。js 。

hx-trigger 用於指定在什麼事件發生時觸發 HTTP 請求,例如:

hx-trigger=“click”

表示在 click 單擊事件發生時

觸發

請求。

hx-trigger 可使用標準網頁事件名,常用事件如下:

load

- 網頁元素首次載入時觸發

請求

click

- 單擊

時觸發

請求

這是除表單,表單控制元件之外所有元素的預設

事件

change

- 控制元件值改變時觸發請求。input,textarea,select 等控制元件的預設

事件

submit

- 提交表單時觸發請求。表單的預設

事件

keydown

- 按鍵時觸發

請求

keyup

- 放開按鍵時觸發

請求

mouseenter

- 滑鼠進入時觸發

請求

mouseleave

- 滑鼠離開時觸發

請求

every 時間 -

定時觸發請求,例如 hx-trgger =

“every 1s”

指定每隔 1 秒傳送一次請求。

事件名後面還可以新增修飾器,例如修飾器 once 表示只允許觸發一次 :

hx-trigger=“click once”

其他事件修飾器:

changed

- 只有在元素的值更改時發出請求

delay:延時

- 在指定的延時後發出請求,例如 hx-trgger =

“load delay:1s”

指定元素載入後延遲 1 秒傳送請求。如果服務端不斷地返回相同 HTML 並替換節點自身,也可以實現輪詢的效果( aardio 後端可以控制何時停止輪詢 )。

throttle:延時

- 節流,避免在指定時間內重複請求

from:CSS選擇器

- 監聽指定元素上的事件。

下面的 HTML 使用了多個事件修飾器:

<

input

type

=

text

hx-trigger

=

keyup changed delay:500ms

hx-post

=

/api/index。aardio

>

這表示在按鍵放開( keyup ),文字框的內容發生改變( changed )時觸發,並且延時 500 毫秒再發送請求。

hx-get 則指定要請求的是哪個後端頁面,例如:

hx-get=“/api/index。aardio”

表示事件觸發時,請求 “/api/index。aardio” 這個頁面。因為 aardio 在啟動 SPA 應用時自動指定了後端根目錄為 “/web”,所以實際請求的是 “/web/api/aardio” 。

而 hx-swap

指定要將返回的 HTML 寫入到哪裡,“innerHTML” 指定是更新網頁節點內部 HTML,“outerHTML” 指定替換目標網頁節點的全部 HTML ,其他還有 “afterbegin” , “beforebegin” , “beforeend” , “afterend” , “none” 。這些看名字就知道是什麼作用,就不解釋了。

hx-target 屬性用 CSS 選擇器指定要寫入的網頁節點,例如:

hx-target=“#info-div”

指定伺服器返回的 HTML 寫入 id 為 “info-div” 的節點。如果省略 hx-target 屬性表示寫入目標是當前節點自身。

hxmx。js 在更新 HTML 時,如果發現新舊 html 中有 id 相同的元素會進行最佳化並平滑顯示。

看到這裡,htmx。js 您已經會用了。

雖然 htmx。js 文件裡有更多花式用法,但一般可能用不上。有些事搞太複雜了也不一定是好事。

htmx。js + aardio 後端

aardio 提供了嵌入式 HTTP 伺服器,可以直接使用 aardio 程式碼寫網頁,支援與 PHP 類似的模板語法。

aardio 的模板語法很簡單,aardio 程式碼寫在 <? ?> 內部,而 HTML 程式碼寫在 <? ?> 外部就可以了。實際上 <? ?>外部的程式碼被轉換為了 aardio 中 print 函式的引數。

例如服務端有下面的 aardio 程式碼:

<

span

>

abc

<

/

span

>

<

response

write

“123”

>

執行後會自動轉換為純 aardio 程式碼如下:

print

abc

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 做這事就很簡單。

我們只要簡單的修改一下前面講過的網頁程式碼如下:

<

button

hx-get

=

/api/index。aardio

hx-indicator

=

#indicator

>

點這裡傳送 GET 請求

button

>

<

br

>

<

img

id

=

indicator

class

=

htmx-indicator

src

=

/images/loading。gif

/>

主要是增加了 hx-indicator 屬性,該屬性的值用一個 CSS 選擇器指定了傳送 HTTP 請求時要顯示的 HTML 元素,這裡指定的是 id 為 “indicator” 的元素。

實際上我們可以自定義這個請求動畫的樣式,我們開啟樣式檔案 index。css 新增下面的樣式:

。htmx-indicator

{

display

none

}

。htmx-request

。htmx-indicator

{

display

inline

}

在傳送請求時,網頁上被設定的指示元素會自動新增 CSS 類 “htmx-request”,HTTP 請求結束會移除該類。

然後我們開啟對應的 aardio 後端程式碼 /web/api/index。aardio ,輸入以下程式碼:

<

span

>

<

if

request

method

==

“GET”

{

/*

這是多執行緒後端,

這裡等 2 秒,網頁會顯示載入動畫

*/

sleep

2000

response

write

time

}

>

<

/

span

>

上面的程式碼的作用是:如果收到 GET 請求,執行緒就休眠 2 秒以模擬耗時操作。然後輸出當前時間。

我們執行一下看看效果:

強大 WebView2 + 不用寫 JavaScript 的 htmx.js快速開發桌面程式

請求引數

htmx。js 提交請求的節點如果是一個表單控制元件,只要指定 name 屬性 —— 就會自動以該名字傳送請求引數,引數值就是控制元件的值。

如果提交請求的節點是表單,則 HTTP 請求引數為表單內所有控制元件的值。

也可以在節點的 hx-vals 屬性中用一個 JSON 物件指定請求引數,例如網頁這樣寫:

<

button

hx-get

=

/api/index。aardio

hx-vals

=

{“myVal”: “值”}

>

點這裡傳送 GET 請求

button

>

<

br

>

aardio 後端就可以使用:

request。get[“myval”]

取到 HTTP 請求引數 myval 的值。

如果使用 POST 傳送請求,例如:

<

button

hx-post

=

/api/index。aardio

hx-vals

=

{“myVal”: “值”}

>

點這裡傳送 GET 請求

button

>

<

br

>

那麼 aardio 後端可以使用

request。post[“myval”]

取到 HTTP 請求引數 myval 的值。

在 aardio 後端使用:

request。query(“myval”)

可以取到 GET 或 POST 傳送的 myval 引數值。

hx-vals 還可以透過加上 javascript: 或者 js: 字首後使用 JS 物件返回請求引數,例如:

<

button

hx-get

=

/api/index。aardio

hx-vals

=

javascript:{myVal: “值”}

>

點這裡傳送 GET 請求

button

>

web。form 也玩 htmx。js

有趣的是 web。form 也可以支援 htmx。js 。

web。form 是基於系統自帶的 IE 核心控制元件,注意系統雖然刪除了 IE 瀏覽器,但 IE 控制元件屬於系統元件,Windows 有說明該控制元件不會被移除。IE 控制元件的好處是從 XP 到 Win11 所有作業系統都自帶。

而且 IE 控制元件很輕量,與本地程式互動的介面也非常方便。Win10 ,Win11 自帶的是 IE11 核心,寫寫一般的網頁還是很好用的。至於 Win7 —— 因為只有極低的份額,一般軟體不用考慮。

強大 WebView2 + 不用寫 JavaScript 的 htmx.js快速開發桌面程式

htmx。js 最後一個支援 IE 11 的版本是 1。6。1 ,這個足夠用了。前面說過我們需要的只是區域性請求重新整理的功能,其他功能我們用不上,所以追新無意義。

首先我們開啟 aardio 工程嚮導,選擇「 Web 介面 > Web Form 」然後建立工程即可,新版工程模板預設就是使用 htmx。js 。

其他 HTML 程式碼寫法與前面介紹的 WebView2 基本一樣。不過 web。form 本就支援 EXE 內嵌資原始檔,所以預設並不會啟動 HTTP 伺服器,需要多寫幾句程式碼。

開啟工程的 webPage。aardio 原始碼:

強大 WebView2 + 不用寫 JavaScript 的 htmx.js快速開發桌面程式

可以看到原始碼中是如下啟動 HTTP 伺服器的:

import

web

form

var

wb

=

web

form

winform

//多執行緒後端

import

wsock

tcp

simpleHttpServer

wsock

tcp

simpleHttpServer

documentBase

=

“\web”

var

indexUrl

=

wsock

tcp

simpleHttpServer

startUrl

“\index。html”

wb

go

indexUrl

我並沒有把這幾句程式碼封裝到 wb。go() 函式中。

有些新手總以為程式碼越少越好,其實並非如此,有時候多寫幾句更容易看清楚程式碼的思路,更容易理解我們正在使用的技術。

下面我們看下 web。form + htmx。js 範例的執行效果:

強大 WebView2 + 不用寫 JavaScript 的 htmx.js快速開發桌面程式

上面示例程式的主視窗是使用 win。ui。tabs 做的,只有其中一個標籤頁用到了網頁。

其實一般桌面軟體的介面並不是一定要全部使用網頁實現。有時候我們將介面中適合用網頁呈現的部分用網頁做,可能會更好。

我們在使用任何技術時,都要考慮一下適不適合。沒有一樣技術能適合做所有的事,多個選擇總是好事。