Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
面客戶端軟件開發(fā)框架是用于創(chuàng)建桌面應(yīng)用程序的工具集合,它們提供了開發(fā)者需要的基本組件、庫和工具,以便于快速構(gòu)建功能豐富、可靠的桌面應(yīng)用程序。以下是一些常用的桌面客戶端軟件開發(fā)框架,希望對(duì)大家有所幫助。北京木奇移動(dòng)技術(shù)有限公司,專業(yè)的軟件外包開發(fā)公司,歡迎交流合作。
1.Electron:Electron 是一個(gè)開源的跨平臺(tái)框架,使用 HTML、CSS 和 JavaScript 構(gòu)建桌面應(yīng)用程序。它基于 Chromium 和 Node.js,支持 Windows、macOS 和 Linux 等多個(gè)平臺(tái)。Electron 由 GitHub 開發(fā),許多知名應(yīng)用如 Slack、Visual Studio Code 和 Discord 都是使用 Electron 構(gòu)建的。
2.Qt:Qt 是一個(gè)跨平臺(tái)的 C++ 應(yīng)用程序開發(fā)框架,提供了豐富的 GUI 組件和工具包,可用于構(gòu)建高性能的桌面應(yīng)用程序。Qt 支持 Windows、macOS、Linux 等主流操作系統(tǒng),以及移動(dòng)平臺(tái)如 Android 和 iOS。它被廣泛應(yīng)用于各種行業(yè)領(lǐng)域,包括汽車、航空航天、醫(yī)療等。
3.JavaFX:JavaFX 是 Java 平臺(tái)的圖形界面框架,用于構(gòu)建豐富的交互式桌面應(yīng)用程序。JavaFX 提供了豐富的 UI 控件、動(dòng)畫效果和多媒體支持,并與 Java 語言緊密集成。JavaFX 可以在 Windows、macOS 和 Linux 等操作系統(tǒng)上運(yùn)行。
4.GTK+:GTK+ 是一個(gè)跨平臺(tái)的 GUI 工具包,使用 C 語言編寫,提供了豐富的界面組件和工具,適用于構(gòu)建 GNOME 桌面環(huán)境下的應(yīng)用程序。GTK+ 支持 Linux、Windows 和 macOS 等操作系統(tǒng)。
5.WPF (Windows Presentation Foundation):WPF 是 Microsoft .NET Framework 的一部分,用于構(gòu)建 Windows 平臺(tái)上的富客戶端應(yīng)用程序。WPF 提供了 XAML 標(biāo)記語言來定義用戶界面,以及強(qiáng)大的數(shù)據(jù)綁定和樣式化功能。
6.Cocoa:Cocoa 是 macOS 平臺(tái)上的應(yīng)用程序開發(fā)框架,使用 Objective-C 或 Swift 編程語言。它提供了豐富的 API 和工具,用于構(gòu)建 macOS 和 iOS 應(yīng)用程序,并與 macOS 操作系統(tǒng)緊密集成。
7.Avalonia:Avalonia 是一個(gè)跨平臺(tái)的 .NET GUI 框架,使用 C# 語言編寫,可用于構(gòu)建 Windows、macOS 和 Linux 上的桌面應(yīng)用程序。Avalonia 的設(shè)計(jì)受到 WPF 和 Xamarin.Forms 的啟發(fā),提供了 XAML 標(biāo)記語言和 MVVM 模式支持。
選擇桌面客戶端軟件開發(fā)框架時(shí),通常需要考慮開發(fā)者的技能水平、項(xiàng)目需求、目標(biāo)平臺(tái)以及性能要求等因素。
騎士是哈啰的一款終端安全應(yīng)用,本文主要介紹我們?cè)谧鲂掳婀T士桌面端時(shí)的一些技術(shù)架構(gòu)思考和實(shí)踐,分享我們沉淀的一些桌面端應(yīng)用的解決方案和經(jīng)驗(yàn)。
為什么選擇Electron
前端開發(fā)者入門快
Electron是一個(gè)使用 JavaScript、HTML 和 CSS 構(gòu)建桌面應(yīng)用程序的框架。嵌入 Chromium 和 Node.js 到 二進(jìn)制的 Electron 允許您保持一個(gè) JavaScript 代碼代碼庫并創(chuàng)建 在Windows上運(yùn)行的跨平臺(tái)應(yīng)用 macOS和Linux——不需要本地開發(fā)經(jīng)驗(yàn),有了它,前端開發(fā)者就可以使用前端開發(fā)技術(shù)來開發(fā)桌面應(yīng)用了。
支持跨端&開發(fā)效率高
如上圖所示:
作為一個(gè)跨平臺(tái)的桌面應(yīng)用開發(fā)框架,Electron 的迷人之處在于,它是建立在 Chromium 和 Node.js 之上的,二位分工明確,一個(gè)負(fù)責(zé)界面,一個(gè)負(fù)責(zé)背后的邏輯。雖然系統(tǒng)間還是會(huì)有很大的差異,需要相應(yīng)地做一些額外處理,使得打包出的應(yīng)用在不同系統(tǒng)下都能正常運(yùn)轉(zhuǎn),但相比于 80% 都能完全復(fù)用的代碼,這些時(shí)間和成本都是可以忽略的,開發(fā)效率直接翻倍,如果你開發(fā)一個(gè)不需要太關(guān)注底層的桌面端應(yīng)用,基本不需要做底層的抹平邏輯。
另外,Electron 是基于 Node.js 的,這就意味著,Node 這個(gè)大生態(tài)下的模塊,Electron 都可以用。同時(shí),跨平臺(tái)也讓 Electron 可同時(shí)開發(fā) Web 應(yīng)用和桌面應(yīng)用,無論是 UI,還是代碼,很多資源都可以共享,大幅減少了開發(fā)者的工作量。
生態(tài)繁榮&案例成熟
Electron生態(tài)的確很強(qiáng)大,各種庫和工具包都為你構(gòu)建一個(gè)桌面端應(yīng)用提供了很多方案。
當(dāng)然,不止如此,現(xiàn)在用Electron做桌面端的案例也非常成熟了。上圖已經(jīng)說明了Electron應(yīng)用是有多廣泛了,這其中不乏大名鼎鼎、如雷貫耳的應(yīng)用,例如 Postman、Skype、VScode 等。而且我敢打賭,各位看官的電腦上一定安裝過用 Electron 開發(fā)的應(yīng)用,如果你用的是 Mac 電腦,請(qǐng)?jiān)诿钚羞\(yùn)行下面的命令來檢測(cè)本地采用 Electron 技術(shù)開發(fā)的桌面軟件:
for app in /Applications/*; do;[ -d $app/Contents/Frameworks/Electron\ Framework.framework ] && echo $app; done
Electron生態(tài)開發(fā)技術(shù)選型
腳手架選型
關(guān)于腳手架的選擇,其實(shí)也很多。
官方提供的有Electron Forge,Electron Fiddle,electron-quick-start,其實(shí)如果你的應(yīng)用不復(fù)雜,可以用官方的腳手架生成一個(gè)快速上手的模版,然后就可以愉快地開發(fā)了。
當(dāng)然也有一些開源的腳手架,比如electron-vue或vue-cli-plugin-electron-builder之類的,也可以讓你快速的生成一個(gè)固定的模版,然后往里面填充你的內(nèi)容。
個(gè)人認(rèn)為,官方的腳手架工具可以用來嘗鮮,學(xué)習(xí)使用,electron-vue這類工具,如果是在一個(gè)企業(yè)級(jí)的項(xiàng)目中使用,前期會(huì)給你帶來便利,但是后期擴(kuò)展不會(huì)太友好,另外就是他們是基于webpack構(gòu)建的工具,在日常的開發(fā)和使用中會(huì)覺得編譯得不夠快(相對(duì)于Vite)。
另外就是如果你想自己完成一個(gè)項(xiàng)目腳手架(項(xiàng)目框架),完全可以憑借自己的經(jīng)驗(yàn)或者參考開源項(xiàng)目的架構(gòu)自己來完成一個(gè)腳手架,一來是為了更加了解Electron的構(gòu)建原理,二來是可以搭建出適合自己風(fēng)格項(xiàng)目的腳手架,后期利于擴(kuò)展和豐富。
所以我們腳手架的選型就是自己來造一個(gè)Electron的項(xiàng)目架構(gòu),從package.json開始,用Vite+Electron+React構(gòu)建一個(gè)Electron項(xiàng)目。
網(wǎng)絡(luò)模塊選型
Electron發(fā)送HTTP請(qǐng)求的方案有很多。
第一種就是渲染進(jìn)程和主進(jìn)程分別用相應(yīng)的請(qǐng)求HTTP請(qǐng)求工具來進(jìn)行網(wǎng)絡(luò)請(qǐng)求,比如渲染進(jìn)程可以使用fetch,主進(jìn)程用net模塊。這種方案的優(yōu)點(diǎn)就是可以把渲染進(jìn)程和主進(jìn)程的請(qǐng)求分開,分工明確,而且調(diào)試也方便,渲染進(jìn)程可以直接看network;缺點(diǎn)就是,如果要對(duì)請(qǐng)求進(jìn)行統(tǒng)一封裝的話,比較麻煩。
第二種就是所有的請(qǐng)求統(tǒng)一封裝,如果你都使用net模塊或者其他的請(qǐng)求工具包對(duì)請(qǐng)求進(jìn)行統(tǒng)一的封裝,然后主進(jìn)程直接使用,渲染進(jìn)程調(diào)用統(tǒng)一的橋接方法。這種方案就是完全可以統(tǒng)一請(qǐng)求封裝,但是如果想調(diào)試的請(qǐng)求的話,不方便,需要在主進(jìn)程來日志信息。
第三種就是,直接axios直接一把梭,它既支持node環(huán)境,也支持瀏覽器環(huán)境。這種方案非常方便,你就按照之前封裝Web應(yīng)用請(qǐng)求的思路去封裝自己的請(qǐng)求模塊就行,不過需要注意跨域問題。
對(duì)于上面的幾種方案,各有各的優(yōu)缺點(diǎn),可以根據(jù)自己的場(chǎng)景需求來決定使用哪種方案。我們選擇了axios來設(shè)計(jì)網(wǎng)絡(luò)請(qǐng)求模塊。
本地?cái)?shù)據(jù)庫選型
Electron的本地?cái)?shù)據(jù)存儲(chǔ)方式也有很多種,可以直接讀寫文件,也可以用相關(guān)的庫,方便數(shù)據(jù)管理。一些庫的對(duì)比,詳情:https://www.npmtrends.com/electron-store-vs-lokijs-vs-lowdb-vs-nedb-vs-realm。
綜合來看lowdb更勝一籌,所以選擇lowdb做本地?cái)?shù)據(jù)庫,非常好的一點(diǎn)是它支持同步,不必?fù)?dān)心數(shù)據(jù)沒有寫入就進(jìn)行了下一步需要本地?cái)?shù)據(jù)的業(yè)務(wù)操作。
日志工具選型
日志工具對(duì)Electron的開發(fā)也是尤為重要的,可以給你定位到一些表層無法定位的問題,所以一款好的日志工具對(duì)開發(fā)是非常有幫助的。
比較常見的日志工具就是electron-log和log4js-node,這兩款日志工具我都有用過。可以看下npm的排行,這里把express-winston和logging也加上看一下,詳情:https://npmtrends.com/electron-log-vs-express-winston-vs-log4js-vs-logging。
這里簡(jiǎn)單說一下electron-log和log4js-node的比較,兩者上手都比較簡(jiǎn)單,log4js-node暴露的API 非常多,electron-log就稍顯遜色了,另外最直觀的感受就是,electron-log的日志文件路徑不好找,暫時(shí)沒發(fā)現(xiàn)自定義日志路徑的方法,log4js-node有相應(yīng)的方法,而且你可以自定義各種文件類型。
根據(jù)使用體驗(yàn),覺得log4js-node更好,推薦log4js-node。
構(gòu)建工具選型
三種構(gòu)建工具electron-builder, electron-forge, electron-packager 對(duì)比一下。
從這個(gè)排行來看electron-builder的確很強(qiáng),electron-forge最近又更新大的版本,不過沒有嘗鮮,我在electron-builder上倒是踩了不少坑,可以分享給大家。所以我在開發(fā)的時(shí)候選擇的構(gòu)建打包工具是electron-builder,它把整套解決方案都集成了,包括打包、更新、簽名、分發(fā),基本的鉤子和配置都有相應(yīng)的暴露。
核心架構(gòu)實(shí)現(xiàn)
架構(gòu)概覽
我們整個(gè)框架是基于Eletcorn + Vite構(gòu)建的,在底層依賴的安全能力和存儲(chǔ)模塊的基礎(chǔ)設(shè)施之上設(shè)計(jì)了一層基礎(chǔ)框架,實(shí)現(xiàn)構(gòu)建打包,架構(gòu)分層的設(shè)計(jì),然后給整個(gè)桌面應(yīng)用提供一些應(yīng)用管理能力和GUI管理相關(guān)的能力,最上層就是為了一些業(yè)務(wù)場(chǎng)景提供的一些應(yīng)用能力,包括核心的幾個(gè)應(yīng)用和主要的策略引擎應(yīng)用(終端策略和合規(guī)策略)。
開發(fā)構(gòu)建
Electron是多進(jìn)程架構(gòu)的體系,所以我們?cè)陂_發(fā)構(gòu)建的時(shí)候就是構(gòu)建多個(gè)進(jìn)程來實(shí)現(xiàn)我們的應(yīng)用。核心思路是通過Vite構(gòu)建三個(gè)進(jìn)程:渲染進(jìn)程,任務(wù)進(jìn)程,主進(jìn)程,然后最后將三個(gè)進(jìn)程融合起來,就形成了一個(gè)應(yīng)用。核心代碼如下:
幾個(gè)注意點(diǎn):
架構(gòu)分層
因?yàn)樾枰缍碎_發(fā),Mac和Windows有些底層模塊的實(shí)現(xiàn)還是有不一樣的地方,所以我們?cè)陂_發(fā)設(shè)計(jì)的時(shí)候?qū)⒋a進(jìn)行了分層設(shè)計(jì),這樣至上而下的調(diào)用在上層看來是一樣的,所以我們需要磨平端上底層的差異,現(xiàn)階段我們底層模塊的實(shí)現(xiàn)是通過目錄來嚴(yán)格區(qū)分的,這樣在開發(fā)一個(gè)底層的功能的時(shí)候就可以做到各段相互不影響。
打包升級(jí)
桌面客戶端相當(dāng)于傳統(tǒng)的Web應(yīng)用在打包和更新這一塊還是有非常大的不同的,傳統(tǒng)的web應(yīng)用幾乎不用所謂的升級(jí),瀏覽器刷新頁面即可,但是桌面客戶端就需要完整的給用戶一個(gè)可以立即執(zhí)行的安裝應(yīng)用程序,而且還要可持續(xù)迭代和更新,所以在打包升級(jí)這一塊,我們也是踩了不少坑。
1. 關(guān)于打包
打包其實(shí)Electron的生態(tài)也是非常成熟的,如上面提到的構(gòu)建技術(shù)選型,我們選擇的是electron-builder,它提供了一套打包構(gòu)建升級(jí)的流程,暴露了很多API,傻瓜式的配置就基本可以讓你實(shí)現(xiàn)一個(gè)應(yīng)用的打包了,唯一麻煩的就是簽名和認(rèn)證應(yīng)用。
在Windows端我們使用pfx格式的證書進(jìn)行認(rèn)證,在進(jìn)行打包的時(shí)候會(huì)和證書客戶端軟件交互,完成各個(gè)文件的簽名,這樣用戶使用客戶端的時(shí)候就是簽名過的軟件了。
在Mac端我們需要使用蘋果認(rèn)證的開發(fā)者證書進(jìn)行簽名和認(rèn)證,配置相應(yīng)的identity后,構(gòu)建打包的時(shí)候會(huì)直接跟你本地的證書進(jìn)行交互,然后對(duì)文件進(jìn)行簽名,當(dāng)前我們還需要讓應(yīng)用可以不必嚴(yán)格使用 MAP_JIT 標(biāo)識(shí)也能寫入和運(yùn)行內(nèi)存內(nèi)容。所以需要加入entitlements和entitlementsInherit。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
</dict>
</plist>
到這一步其實(shí)Mac端的軟件簽名就完成了,但是如果應(yīng)用想App Store上架的話還需要對(duì)應(yīng)用進(jìn)行公證。公證主要是使用electron-notarize來進(jìn)行公證,啟用afterSign即可,
afterSign: './script/notarize.js',
下面的Apple ID就是你的開發(fā)者賬號(hào),appleIdPassword需要生成一個(gè)專用的應(yīng)用密碼,不要使用你本來的Apple ID密碼。
const { notarize }=require("electron-notarize");
exports.default=async function notarizing(context) {
const { electronPlatformName, appOutDir }=context;
if (electronPlatformName !=="darwin") {
return;
}
const appName=context.packager.appInfo.productFilename;
console.log(\`公證中...\`)
return await notarize({
appBundleId: "mac.hellobike.knight",
appPath: \`${appOutDir}/${appName}.app\`,1
appleId: "XXXXX@outlook.com",
appleIdPassword: "XXXXX",
});
};
notarize會(huì)根據(jù)你的配置去校驗(yàn)?zāi)愕膽?yīng)用是否可以公證成功,公證的時(shí)候會(huì)和蘋果的服務(wù)器進(jìn)行通訊,所以需要保持網(wǎng)絡(luò)不要斷開,成功或者失敗之后都會(huì)發(fā)送相應(yīng)的郵件到你的開發(fā)者郵箱里面。
到這里打包的核心工作就做完了,如果你需要其他個(gè)性化配置,參考electron-builder官方的文檔即可。
2. 關(guān)于升級(jí)
升級(jí)我們?cè)贛ac和Windows上的實(shí)現(xiàn)各有不同,因?yàn)橄啾扔趥鹘y(tǒng)的軟件,我們哈騎士會(huì)一直保活在用戶的進(jìn)程中,所以在更新升級(jí)的時(shí)候也會(huì)打破原本Electron升級(jí)的機(jī)制。
在Windows上其實(shí)還好,可以利用electron-updater本身的生命周期來完成下載,更新,重啟應(yīng)用,因?yàn)閃indows的保活是用另外的服務(wù)來實(shí)現(xiàn)的,所以并不會(huì)對(duì)整個(gè)更新周期產(chǎn)生破壞性的影響。
但是Mac端的保活實(shí)現(xiàn)是打破了electron-updater本身的生命周期的,探究其源碼會(huì)發(fā)現(xiàn)Electron自己的升級(jí)服務(wù)其實(shí)也是一個(gè)保活的應(yīng)用服務(wù),所以在升級(jí)之前需要將其Kill后才能完成哈騎士自己本身的更新邏輯,另外就是文件占用和鎖定的問題,為此我們自研了一套更新腳本程序結(jié)合electron-updater的下載更新的能力實(shí)現(xiàn)了Mac端軟件的升級(jí)。
核心能力沉淀
基礎(chǔ)能力
我們?cè)谧龉T士客戶端的時(shí)候,也沉淀了一些與業(yè)務(wù)無耦合的組件和工具類,這些組件和工具在桌面端應(yīng)用的場(chǎng)景都比較通用。
應(yīng)用能力
在上面這些基礎(chǔ)能力的組合應(yīng)用下,我們形成了一個(gè)強(qiáng)大的策略引擎應(yīng)用。
該策略引擎應(yīng)用實(shí)現(xiàn)了端上任務(wù)調(diào)度和分發(fā)功能。首先接收后臺(tái)配置的策略信息,然后生成對(duì)應(yīng)的任務(wù),并分發(fā)到各個(gè)子任務(wù)中心以執(zhí)行對(duì)應(yīng)的策略。最后,將策略執(zhí)行情況報(bào)告給服務(wù)端。
總結(jié)
Electron在哈騎士的應(yīng)用非常成功,雖然在使用過程中遇到了一些問題,但不可否認(rèn)它是目前最適合我們業(yè)務(wù)目標(biāo)和開發(fā)資源的框架。使用Electron使需求交付效率得到了很大的提升。
我們也將持續(xù)關(guān)注性能和穩(wěn)定性的優(yōu)化、桌面端全鏈路日志的完善以及增量更新升級(jí)能力等方面的改進(jìn)。
作者:徐濤燾
來源:微信公眾號(hào):哈啰技術(shù)
出處:https://mp.weixin.qq.com/s/8v5lyl-yI4AMxQgSwDmkWw
ebView2 是越來越香了。
WebView2 不但是 Win11 自帶的系統(tǒng)組件,Win10 也已經(jīng)自動(dòng)推送安裝。即使是少量沒有安裝 WebView2 的系統(tǒng) —— 使用 aardio 中的 web.view 也會(huì)自動(dòng)安裝( 不需要寫任何代碼 )。
我用 WebView2 開發(fā)了很多項(xiàng)目,不得不說 WebView2 穩(wěn)定可靠、性能強(qiáng)悍,接口簡(jiǎn)潔,是真的讓人省心。
這里介紹一個(gè)適合用于 WebView2 的極簡(jiǎn)前端組件 htmx.js ,這個(gè)組件最大的特色就是簡(jiǎn)單,一學(xué)就會(huì),也很容易理解。
我們正常瀏覽一個(gè)網(wǎng)頁的過程是在瀏覽器里輸入網(wǎng)址,向 HTTP 服務(wù)器發(fā)送請(qǐng)求。然后服務(wù)器返回 HTML 代碼,瀏覽器顯示頁面。
但是 htmx.js 腦洞大開,讓網(wǎng)頁上的每一個(gè) HTML 節(jié)點(diǎn)都可以向服務(wù)器發(fā)送請(qǐng)求并獲取 HTML,并實(shí)時(shí)更新頁面上指定的節(jié)點(diǎn)。而且不需要寫任何 JavaScript 代碼。
首先我們打開 aardio ,創(chuàng)建 WebView2 工程并選擇 htmx.js 模板:
生成的工程如下:
點(diǎn)『運(yùn)行』可直接測(cè)試效果,點(diǎn)『發(fā)布』可生成獨(dú)立 EXE 文件 。
在工程管理器中右鍵點(diǎn)『網(wǎng)頁』彈出菜單,然后點(diǎn)『用外部編輯器打開』,如果安裝了 VS Code 會(huì)使用 VS Code 打開網(wǎng)頁目錄。
在 VS Code 中點(diǎn)擊并打開 index.html 源碼:
打開 index.html ,先看最簡(jiǎn)單的 htmx.js 示例:
<button hx-get="/api/index.aardio"
hx-swap="innerHTML"
hx-trigger="click"
hx-target="#info-div" >
點(diǎn)這里發(fā)送 GET 請(qǐng)求
</button><br>
<div id="info-div"></div>
注意看凡是 "hx-" 前綴的屬性都是用于 htmx.js 。
hx-trigger 用于指定在什么事件發(fā)生時(shí)觸發(fā) HTTP 請(qǐng)求,例如:
hx-trigger="click"
表示在 click 單擊事件發(fā)生時(shí)觸發(fā)請(qǐng)求。
hx-trigger 可使用標(biāo)準(zhǔn)網(wǎng)頁事件名,常用事件如下:
事件名后面還可以添加修飾器,例如修飾器 once 表示只允許觸發(fā)一次 :
hx-trigger="click once"
其他事件修飾器:
下面的 HTML 使用了多個(gè)事件修飾器:
<input type="text"
hx-trigger="keyup changed delay:500ms"
hx-post="/api/index.aardio" >
這表示在按鍵放開( keyup ),文本框的內(nèi)容發(fā)生改變( changed )時(shí)觸發(fā),并且延時(shí) 500 毫秒再發(fā)送請(qǐng)求。
hx-get 則指定要請(qǐng)求的是哪個(gè)后端頁面,例如:
hx-get="/api/index.aardio"
表示事件觸發(fā)時(shí),請(qǐng)求 "/api/index.aardio" 這個(gè)頁面。因?yàn)?aardio 在啟動(dòng) SPA 應(yīng)用時(shí)自動(dòng)指定了后端根目錄為 "/web",所以實(shí)際請(qǐng)求的是 "/web/api/aardio" 。
而 hx-swap 則指定要將返回的 HTML 寫入到哪里,"innerHTML" 指定是更新網(wǎng)頁節(jié)點(diǎn)內(nèi)部 HTML,"outerHTML" 指定替換目標(biāo)網(wǎng)頁節(jié)點(diǎn)的全部 HTML ,其他還有 "afterbegin" , "beforebegin" , "beforeend" , "afterend" , "none" 。這些看名字就知道是什么作用,就不解釋了。
hx-target 屬性用 CSS 選擇器指定要寫入的網(wǎng)頁節(jié)點(diǎn),例如:
hx-target="#info-div"
指定服務(wù)器返回的 HTML 寫入 id 為 "info-div" 的節(jié)點(diǎn)。如果省略 hx-target 屬性表示寫入目標(biāo)是當(dāng)前節(jié)點(diǎn)自身。
hxmx.js 在更新 HTML 時(shí),如果發(fā)現(xiàn)新舊 html 中有 id 相同的元素會(huì)進(jìn)行優(yōu)化并平滑顯示。
看到這里,htmx.js 您已經(jīng)會(huì)用了。
雖然 htmx.js 文檔里有更多花式用法,但一般可能用不上。有些事搞太復(fù)雜了也不一定是好事。
aardio 提供了嵌入式 HTTP 服務(wù)器,可以直接使用 aardio 代碼寫網(wǎng)頁,支持與 PHP 類似的模板語法。
aardio 的模板語法很簡(jiǎn)單,aardio 代碼寫在 <? ?> 內(nèi)部,而 HTML 代碼寫在 <? ?> 外部就可以了。實(shí)際上 <? ?>外部的代碼被轉(zhuǎn)換為了 aardio 中 print 函數(shù)的參數(shù)。
例如服務(wù)端有下面的 aardio 代碼:
<span>abc</span>
<?
response.write("123")
?>
運(yùn)行后會(huì)自動(dòng)轉(zhuǎn)換為純 aardio 代碼如下:
print("<span>abc</span>");
response.write("123");
在 HTTP 后端中,print 函數(shù)實(shí)際上就是指向用于向 HTTP 客戶端輸出數(shù)據(jù)的 response.write() 函數(shù)。
在 HTTP 后端有兩個(gè)最常用的對(duì)象,request 對(duì)象包含了所有 HTTP 請(qǐng)求信息,而 response 對(duì)象為 HTTP 響應(yīng)對(duì)象,用于向客戶端發(fā)送數(shù)據(jù)。
打開 aardio 自帶「工具 > 庫函數(shù)文檔」,點(diǎn)擊 fastcgi.client 的文檔可以查看 request, response 對(duì)象的所有屬性與方法。aardio 中的所有 HTTP 服務(wù)端實(shí)現(xiàn)都統(tǒng)一兼容 fastcgi.client 文檔規(guī)定的 request, response 用法。
也可以參考 aardio 開始頁的 《 aardio 網(wǎng)站開發(fā)、FastCGI開發(fā)入門教程 》。至于 aardio 模板語法,請(qǐng)參考 《 aardio 語法與使用手冊(cè) > aardio 語言 > 模板語法 》
aardio 的模板語法不僅僅可以用于寫 HTTP 后端,也不僅僅是可以用于輸出 HTML,實(shí)際上可以用于生成任何字符串。aardio 中的很多功能都支持這種模板語法,例如運(yùn)行時(shí)編譯 C# 代碼就支持用 aardio 模板語法生成 C# 代碼。另外 aardio 提供 string.loadcode() 函數(shù)可以直接解析 aardio 模板并返回字符串。
這里要注意,上面范例工程默認(rèn)導(dǎo)入的 HTTP 服務(wù)器是:
wsock.tcp.simpleHttpServer;
這是一個(gè)多線程的 HTTP 服務(wù)端,每次被請(qǐng)求執(zhí)行的 aardio 代碼都是在后臺(tái)線程中運(yùn)行。aardio 多線程開發(fā)要注意的是每個(gè)線程都運(yùn)行在獨(dú)立的環(huán)境,全局變量是相互隔離的,這個(gè)限制實(shí)際上讓 aardio 的多線程開發(fā)更簡(jiǎn)潔,坑更少,具體請(qǐng)參考 aardio 自帶「范例程序 > aardio 語言 > 多線程」。
如果改為 wsock.tcp.asynHttpServer 則是單線程異步的 HTTP 服務(wù)器。
下面我們?nèi)匀皇褂媚J(rèn)的 simpleHttpServer 。多線程的好處是耗時(shí)操作不會(huì)卡界面。后端在進(jìn)行耗時(shí)操作時(shí),網(wǎng)頁前端通常需要顯示一個(gè)動(dòng)畫,htmx.js 做這事就很簡(jiǎn)單。
我們只要簡(jiǎn)單的修改一下前面講過的網(wǎng)頁代碼如下:
<button hx-get="/api/index.aardio"
hx-indicator="#indicator" >
點(diǎn)這里發(fā)送 GET 請(qǐng)求
</button><br>
<img id="indicator"
class="htmx-indicator"
src="/images/loading.gif"/>
主要是增加了 hx-indicator 屬性,該屬性的值用一個(gè) CSS 選擇器指定了發(fā)送 HTTP 請(qǐng)求時(shí)要顯示的 HTML 元素,這里指定的是 id 為 "indicator" 的元素。
實(shí)際上我們可以自定義這個(gè)請(qǐng)求動(dòng)畫的樣式,我們打開樣式文件 index.css 添加下面的樣式:
.htmx-indicator{
display:none;
}
.htmx-request.htmx-indicator{
display:inline;
}
在發(fā)送請(qǐng)求時(shí),網(wǎng)頁上被設(shè)定的指示元素會(huì)自動(dòng)添加 CSS 類 "htmx-request",HTTP 請(qǐng)求結(jié)束會(huì)移除該類。
然后我們打開對(duì)應(yīng)的 aardio 后端代碼 /web/api/index.aardio ,輸入以下代碼:
<span>
<?
if( request.method=="GET"){
/*
這是多線程后端,
這里等 2 秒,網(wǎng)頁會(huì)顯示加載動(dòng)畫
*/
sleep(2000);
response.write( time() )
}
?></span>
上面的代碼的作用是:如果收到 GET 請(qǐng)求,線程就休眠 2 秒以模擬耗時(shí)操作。然后輸出當(dāng)前時(shí)間。
我們運(yùn)行一下看看效果:
htmx.js 提交請(qǐng)求的節(jié)點(diǎn)如果是一個(gè)表單控件,只要指定 name 屬性 —— 就會(huì)自動(dòng)以該名字發(fā)送請(qǐng)求參數(shù),參數(shù)值就是控件的值。
如果提交請(qǐng)求的節(jié)點(diǎn)是表單,則 HTTP 請(qǐng)求參數(shù)為表單內(nèi)所有控件的值。
也可以在節(jié)點(diǎn)的 hx-vals 屬性中用一個(gè) JSON 對(duì)象指定請(qǐng)求參數(shù),例如網(wǎng)頁這樣寫:
<button hx-get="/api/index.aardio"
hx-vals='{"myVal": "值"}'>
點(diǎn)這里發(fā)送 GET 請(qǐng)求
</button><br>
aardio 后端就可以使用:
request.get["myval"]
取到 HTTP 請(qǐng)求參數(shù) myval 的值。
如果使用 POST 發(fā)送請(qǐng)求,例如:
<button hx-post="/api/index.aardio"
hx-vals='{"myVal": "值"}'>
點(diǎn)這里發(fā)送 GET 請(qǐng)求
</button><br>
那么 aardio 后端可以使用
request.post["myval"]
取到 HTTP 請(qǐng)求參數(shù) myval 的值。
在 aardio 后端使用:
request.query("myval")
可以取到 GET 或 POST 發(fā)送的 myval 參數(shù)值。
hx-vals 還可以通過加上 javascript: 或者 js: 前綴后使用 JS 對(duì)象返回請(qǐng)求參數(shù),例如:
<button hx-get="/api/index.aardio"
hx-vals='javascript:{myVal: "值"}' >
點(diǎn)這里發(fā)送 GET 請(qǐng)求
</button>
有趣的是 web.form 也可以支持 htmx.js 。
web.form 是基于系統(tǒng)自帶的 IE 內(nèi)核控件,注意系統(tǒng)雖然刪除了 IE 瀏覽器,但 IE 控件屬于系統(tǒng)組件,Windows 有說明該控件不會(huì)被移除。IE 控件的好處是從 XP 到 Win11 所有操作系統(tǒng)都自帶。
而且 IE 控件很輕量,與本地程序交互的接口也非常方便。Win10 ,Win11 自帶的是 IE11 內(nèi)核,寫寫一般的網(wǎng)頁還是很好用的。至于 Win7 —— 因?yàn)橹挥袠O低的份額,一般軟件不用考慮。
htmx.js 最后一個(gè)支持 IE 11 的版本是 1.6.1 ,這個(gè)足夠用了。前面說過我們需要的只是局部請(qǐng)求刷新的功能,其他功能我們用不上,所以追新無意義。
首先我們打開 aardio 工程向?qū)Вx擇「 Web 界面 > Web Form 」然后創(chuàng)建工程即可,新版工程模板默認(rèn)就是使用 htmx.js 。
其他 HTML 代碼寫法與前面介紹的 WebView2 基本一樣。不過 web.form 本就支持 EXE 內(nèi)嵌資源文件,所以默認(rèn)并不會(huì)啟動(dòng) HTTP 服務(wù)器,需要多寫幾句代碼。
打開工程的 webPage.aardio 源碼:
可以看到源碼中是如下啟動(dòng) HTTP 服務(wù)器的:
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() 函數(shù)中。
有些新手總以為代碼越少越好,其實(shí)并非如此,有時(shí)候多寫幾句更容易看清楚代碼的思路,更容易理解我們正在使用的技術(shù)。
下面我們看下 web.form + htmx.js 范例的運(yùn)行效果:
上面示例程序的主窗口是使用 win.ui.tabs 做的,只有其中一個(gè)標(biāo)簽頁用到了網(wǎng)頁。
其實(shí)一般桌面軟件的界面并不是一定要全部使用網(wǎng)頁實(shí)現(xiàn)。有時(shí)候我們將界面中適合用網(wǎng)頁呈現(xiàn)的部分用網(wǎng)頁做,可能會(huì)更好。
我們?cè)谑褂萌魏渭夹g(shù)時(shí),都要考慮一下適不適合。沒有一樣技術(shù)能適合做所有的事,多個(gè)選擇總是好事。
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。