面客戶端軟件開發框架是用于創建桌面應用程序的工具集合,它們提供了開發者需要的基本組件、庫和工具,以便于快速構建功能豐富、可靠的桌面應用程序。以下是一些常用的桌面客戶端軟件開發框架,希望對大家有所幫助。北京木奇移動技術有限公司,專業的軟件外包開發公司,歡迎交流合作。
1.Electron:Electron 是一個開源的跨平臺框架,使用 HTML、CSS 和 JavaScript 構建桌面應用程序。它基于 Chromium 和 Node.js,支持 Windows、macOS 和 Linux 等多個平臺。Electron 由 GitHub 開發,許多知名應用如 Slack、Visual Studio Code 和 Discord 都是使用 Electron 構建的。
2.Qt:Qt 是一個跨平臺的 C++ 應用程序開發框架,提供了豐富的 GUI 組件和工具包,可用于構建高性能的桌面應用程序。Qt 支持 Windows、macOS、Linux 等主流操作系統,以及移動平臺如 Android 和 iOS。它被廣泛應用于各種行業領域,包括汽車、航空航天、醫療等。
3.JavaFX:JavaFX 是 Java 平臺的圖形界面框架,用于構建豐富的交互式桌面應用程序。JavaFX 提供了豐富的 UI 控件、動畫效果和多媒體支持,并與 Java 語言緊密集成。JavaFX 可以在 Windows、macOS 和 Linux 等操作系統上運行。
4.GTK+:GTK+ 是一個跨平臺的 GUI 工具包,使用 C 語言編寫,提供了豐富的界面組件和工具,適用于構建 GNOME 桌面環境下的應用程序。GTK+ 支持 Linux、Windows 和 macOS 等操作系統。
5.WPF (Windows Presentation Foundation):WPF 是 Microsoft .NET Framework 的一部分,用于構建 Windows 平臺上的富客戶端應用程序。WPF 提供了 XAML 標記語言來定義用戶界面,以及強大的數據綁定和樣式化功能。
6.Cocoa:Cocoa 是 macOS 平臺上的應用程序開發框架,使用 Objective-C 或 Swift 編程語言。它提供了豐富的 API 和工具,用于構建 macOS 和 iOS 應用程序,并與 macOS 操作系統緊密集成。
7.Avalonia:Avalonia 是一個跨平臺的 .NET GUI 框架,使用 C# 語言編寫,可用于構建 Windows、macOS 和 Linux 上的桌面應用程序。Avalonia 的設計受到 WPF 和 Xamarin.Forms 的啟發,提供了 XAML 標記語言和 MVVM 模式支持。
選擇桌面客戶端軟件開發框架時,通常需要考慮開發者的技能水平、項目需求、目標平臺以及性能要求等因素。
騎士是哈啰的一款終端安全應用,本文主要介紹我們在做新版哈騎士桌面端時的一些技術架構思考和實踐,分享我們沉淀的一些桌面端應用的解決方案和經驗。
為什么選擇Electron
前端開發者入門快
Electron是一個使用 JavaScript、HTML 和 CSS 構建桌面應用程序的框架。嵌入 Chromium 和 Node.js 到 二進制的 Electron 允許您保持一個 JavaScript 代碼代碼庫并創建 在Windows上運行的跨平臺應用 macOS和Linux——不需要本地開發經驗,有了它,前端開發者就可以使用前端開發技術來開發桌面應用了。
支持跨端&開發效率高
如上圖所示:
作為一個跨平臺的桌面應用開發框架,Electron 的迷人之處在于,它是建立在 Chromium 和 Node.js 之上的,二位分工明確,一個負責界面,一個負責背后的邏輯。雖然系統間還是會有很大的差異,需要相應地做一些額外處理,使得打包出的應用在不同系統下都能正常運轉,但相比于 80% 都能完全復用的代碼,這些時間和成本都是可以忽略的,開發效率直接翻倍,如果你開發一個不需要太關注底層的桌面端應用,基本不需要做底層的抹平邏輯。
另外,Electron 是基于 Node.js 的,這就意味著,Node 這個大生態下的模塊,Electron 都可以用。同時,跨平臺也讓 Electron 可同時開發 Web 應用和桌面應用,無論是 UI,還是代碼,很多資源都可以共享,大幅減少了開發者的工作量。
生態繁榮&案例成熟
Electron生態的確很強大,各種庫和工具包都為你構建一個桌面端應用提供了很多方案。
當然,不止如此,現在用Electron做桌面端的案例也非常成熟了。上圖已經說明了Electron應用是有多廣泛了,這其中不乏大名鼎鼎、如雷貫耳的應用,例如 Postman、Skype、VScode 等。而且我敢打賭,各位看官的電腦上一定安裝過用 Electron 開發的應用,如果你用的是 Mac 電腦,請在命令行運行下面的命令來檢測本地采用 Electron 技術開發的桌面軟件:
for app in /Applications/*; do;[ -d $app/Contents/Frameworks/Electron\ Framework.framework ] && echo $app; done
Electron生態開發技術選型
腳手架選型
關于腳手架的選擇,其實也很多。
官方提供的有Electron Forge,Electron Fiddle,electron-quick-start,其實如果你的應用不復雜,可以用官方的腳手架生成一個快速上手的模版,然后就可以愉快地開發了。
當然也有一些開源的腳手架,比如electron-vue或vue-cli-plugin-electron-builder之類的,也可以讓你快速的生成一個固定的模版,然后往里面填充你的內容。
個人認為,官方的腳手架工具可以用來嘗鮮,學習使用,electron-vue這類工具,如果是在一個企業級的項目中使用,前期會給你帶來便利,但是后期擴展不會太友好,另外就是他們是基于webpack構建的工具,在日常的開發和使用中會覺得編譯得不夠快(相對于Vite)。
另外就是如果你想自己完成一個項目腳手架(項目框架),完全可以憑借自己的經驗或者參考開源項目的架構自己來完成一個腳手架,一來是為了更加了解Electron的構建原理,二來是可以搭建出適合自己風格項目的腳手架,后期利于擴展和豐富。
所以我們腳手架的選型就是自己來造一個Electron的項目架構,從package.json開始,用Vite+Electron+React構建一個Electron項目。
網絡模塊選型
Electron發送HTTP請求的方案有很多。
第一種就是渲染進程和主進程分別用相應的請求HTTP請求工具來進行網絡請求,比如渲染進程可以使用fetch,主進程用net模塊。這種方案的優點就是可以把渲染進程和主進程的請求分開,分工明確,而且調試也方便,渲染進程可以直接看network;缺點就是,如果要對請求進行統一封裝的話,比較麻煩。
第二種就是所有的請求統一封裝,如果你都使用net模塊或者其他的請求工具包對請求進行統一的封裝,然后主進程直接使用,渲染進程調用統一的橋接方法。這種方案就是完全可以統一請求封裝,但是如果想調試的請求的話,不方便,需要在主進程來日志信息。
第三種就是,直接axios直接一把梭,它既支持node環境,也支持瀏覽器環境。這種方案非常方便,你就按照之前封裝Web應用請求的思路去封裝自己的請求模塊就行,不過需要注意跨域問題。
對于上面的幾種方案,各有各的優缺點,可以根據自己的場景需求來決定使用哪種方案。我們選擇了axios來設計網絡請求模塊。
本地數據庫選型
Electron的本地數據存儲方式也有很多種,可以直接讀寫文件,也可以用相關的庫,方便數據管理。一些庫的對比,詳情:https://www.npmtrends.com/electron-store-vs-lokijs-vs-lowdb-vs-nedb-vs-realm。
綜合來看lowdb更勝一籌,所以選擇lowdb做本地數據庫,非常好的一點是它支持同步,不必擔心數據沒有寫入就進行了下一步需要本地數據的業務操作。
日志工具選型
日志工具對Electron的開發也是尤為重要的,可以給你定位到一些表層無法定位的問題,所以一款好的日志工具對開發是非常有幫助的。
比較常見的日志工具就是electron-log和log4js-node,這兩款日志工具我都有用過??梢钥聪耼pm的排行,這里把express-winston和logging也加上看一下,詳情:https://npmtrends.com/electron-log-vs-express-winston-vs-log4js-vs-logging。
這里簡單說一下electron-log和log4js-node的比較,兩者上手都比較簡單,log4js-node暴露的API 非常多,electron-log就稍顯遜色了,另外最直觀的感受就是,electron-log的日志文件路徑不好找,暫時沒發現自定義日志路徑的方法,log4js-node有相應的方法,而且你可以自定義各種文件類型。
根據使用體驗,覺得log4js-node更好,推薦log4js-node。
構建工具選型
三種構建工具electron-builder, electron-forge, electron-packager 對比一下。
從這個排行來看electron-builder的確很強,electron-forge最近又更新大的版本,不過沒有嘗鮮,我在electron-builder上倒是踩了不少坑,可以分享給大家。所以我在開發的時候選擇的構建打包工具是electron-builder,它把整套解決方案都集成了,包括打包、更新、簽名、分發,基本的鉤子和配置都有相應的暴露。
核心架構實現
架構概覽
我們整個框架是基于Eletcorn + Vite構建的,在底層依賴的安全能力和存儲模塊的基礎設施之上設計了一層基礎框架,實現構建打包,架構分層的設計,然后給整個桌面應用提供一些應用管理能力和GUI管理相關的能力,最上層就是為了一些業務場景提供的一些應用能力,包括核心的幾個應用和主要的策略引擎應用(終端策略和合規策略)。
開發構建
Electron是多進程架構的體系,所以我們在開發構建的時候就是構建多個進程來實現我們的應用。核心思路是通過Vite構建三個進程:渲染進程,任務進程,主進程,然后最后將三個進程融合起來,就形成了一個應用。核心代碼如下:
幾個注意點:
架構分層
因為需要跨端開發,Mac和Windows有些底層模塊的實現還是有不一樣的地方,所以我們在開發設計的時候將代碼進行了分層設計,這樣至上而下的調用在上層看來是一樣的,所以我們需要磨平端上底層的差異,現階段我們底層模塊的實現是通過目錄來嚴格區分的,這樣在開發一個底層的功能的時候就可以做到各段相互不影響。
打包升級
桌面客戶端相當于傳統的Web應用在打包和更新這一塊還是有非常大的不同的,傳統的web應用幾乎不用所謂的升級,瀏覽器刷新頁面即可,但是桌面客戶端就需要完整的給用戶一個可以立即執行的安裝應用程序,而且還要可持續迭代和更新,所以在打包升級這一塊,我們也是踩了不少坑。
1. 關于打包
打包其實Electron的生態也是非常成熟的,如上面提到的構建技術選型,我們選擇的是electron-builder,它提供了一套打包構建升級的流程,暴露了很多API,傻瓜式的配置就基本可以讓你實現一個應用的打包了,唯一麻煩的就是簽名和認證應用。
在Windows端我們使用pfx格式的證書進行認證,在進行打包的時候會和證書客戶端軟件交互,完成各個文件的簽名,這樣用戶使用客戶端的時候就是簽名過的軟件了。
在Mac端我們需要使用蘋果認證的開發者證書進行簽名和認證,配置相應的identity后,構建打包的時候會直接跟你本地的證書進行交互,然后對文件進行簽名,當前我們還需要讓應用可以不必嚴格使用 MAP_JIT 標識也能寫入和運行內存內容。所以需要加入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>
到這一步其實Mac端的軟件簽名就完成了,但是如果應用想App Store上架的話還需要對應用進行公證。公證主要是使用electron-notarize來進行公證,啟用afterSign即可,
afterSign: './script/notarize.js',
下面的Apple ID就是你的開發者賬號,appleIdPassword需要生成一個專用的應用密碼,不要使用你本來的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會根據你的配置去校驗你的應用是否可以公證成功,公證的時候會和蘋果的服務器進行通訊,所以需要保持網絡不要斷開,成功或者失敗之后都會發送相應的郵件到你的開發者郵箱里面。
到這里打包的核心工作就做完了,如果你需要其他個性化配置,參考electron-builder官方的文檔即可。
2. 關于升級
升級我們在Mac和Windows上的實現各有不同,因為相比于傳統的軟件,我們哈騎士會一直?;钤谟脩舻倪M程中,所以在更新升級的時候也會打破原本Electron升級的機制。
在Windows上其實還好,可以利用electron-updater本身的生命周期來完成下載,更新,重啟應用,因為Windows的?;钍怯昧硗獾姆諄韺崿F的,所以并不會對整個更新周期產生破壞性的影響。
但是Mac端的?;顚崿F是打破了electron-updater本身的生命周期的,探究其源碼會發現Electron自己的升級服務其實也是一個?;畹膽梅眨栽谏壷靶枰獙⑵銴ill后才能完成哈騎士自己本身的更新邏輯,另外就是文件占用和鎖定的問題,為此我們自研了一套更新腳本程序結合electron-updater的下載更新的能力實現了Mac端軟件的升級。
核心能力沉淀
基礎能力
我們在做哈騎士客戶端的時候,也沉淀了一些與業務無耦合的組件和工具類,這些組件和工具在桌面端應用的場景都比較通用。
應用能力
在上面這些基礎能力的組合應用下,我們形成了一個強大的策略引擎應用。
該策略引擎應用實現了端上任務調度和分發功能。首先接收后臺配置的策略信息,然后生成對應的任務,并分發到各個子任務中心以執行對應的策略。最后,將策略執行情況報告給服務端。
總結
Electron在哈騎士的應用非常成功,雖然在使用過程中遇到了一些問題,但不可否認它是目前最適合我們業務目標和開發資源的框架。使用Electron使需求交付效率得到了很大的提升。
我們也將持續關注性能和穩定性的優化、桌面端全鏈路日志的完善以及增量更新升級能力等方面的改進。
作者:徐濤燾
來源:微信公眾號:哈啰技術
出處:https://mp.weixin.qq.com/s/8v5lyl-yI4AMxQgSwDmkWw
ebView2 是越來越香了。
WebView2 不但是 Win11 自帶的系統組件,Win10 也已經自動推送安裝。即使是少量沒有安裝 WebView2 的系統 —— 使用 aardio 中的 web.view 也會自動安裝( 不需要寫任何代碼 )。
我用 WebView2 開發了很多項目,不得不說 WebView2 穩定可靠、性能強悍,接口簡潔,是真的讓人省心。
這里介紹一個適合用于 WebView2 的極簡前端組件 htmx.js ,這個組件最大的特色就是簡單,一學就會,也很容易理解。
我們正常瀏覽一個網頁的過程是在瀏覽器里輸入網址,向 HTTP 服務器發送請求。然后服務器返回 HTML 代碼,瀏覽器顯示頁面。
但是 htmx.js 腦洞大開,讓網頁上的每一個 HTML 節點都可以向服務器發送請求并獲取 HTML,并實時更新頁面上指定的節點。而且不需要寫任何 JavaScript 代碼。
首先我們打開 aardio ,創建 WebView2 工程并選擇 htmx.js 模板:
生成的工程如下:
點『運行』可直接測試效果,點『發布』可生成獨立 EXE 文件 。
在工程管理器中右鍵點『網頁』彈出菜單,然后點『用外部編輯器打開』,如果安裝了 VS Code 會使用 VS Code 打開網頁目錄。
在 VS Code 中點擊并打開 index.html 源碼:
打開 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 可使用標準網頁事件名,常用事件如下:
事件名后面還可以添加修飾器,例如修飾器 once 表示只允許觸發一次 :
hx-trigger="click once"
其他事件修飾器:
下面的 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 文檔里有更多花式用法,但一般可能用不上。有些事搞太復雜了也不一定是好事。
aardio 提供了嵌入式 HTTP 服務器,可以直接使用 aardio 代碼寫網頁,支持與 PHP 類似的模板語法。
aardio 的模板語法很簡單,aardio 代碼寫在 <? ?> 內部,而 HTML 代碼寫在 <? ?> 外部就可以了。實際上 <? ?>外部的代碼被轉換為了 aardio 中 print 函數的參數。
例如服務端有下面的 aardio 代碼:
<span>abc</span>
<?
response.write("123")
?>
運行后會自動轉換為純 aardio 代碼如下:
print("<span>abc</span>");
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 模板并返回字符串。
這里要注意,上面范例工程默認導入的 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 秒以模擬耗時操作。然后輸出當前時間。
我們運行一下看看效果:
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 是基于系統自帶的 IE 內核控件,注意系統雖然刪除了 IE 瀏覽器,但 IE 控件屬于系統組件,Windows 有說明該控件不會被移除。IE 控件的好處是從 XP 到 Win11 所有操作系統都自帶。
而且 IE 控件很輕量,與本地程序交互的接口也非常方便。Win10 ,Win11 自帶的是 IE11 內核,寫寫一般的網頁還是很好用的。至于 Win7 —— 因為只有極低的份額,一般軟件不用考慮。
htmx.js 最后一個支持 IE 11 的版本是 1.6.1 ,這個足夠用了。前面說過我們需要的只是局部請求刷新的功能,其他功能我們用不上,所以追新無意義。
首先我們打開 aardio 工程向導,選擇「 Web 界面 > Web Form 」然后創建工程即可,新版工程模板默認就是使用 htmx.js 。
其他 HTML 代碼寫法與前面介紹的 WebView2 基本一樣。不過 web.form 本就支持 EXE 內嵌資源文件,所以默認并不會啟動 HTTP 服務器,需要多寫幾句代碼。
打開工程的 webPage.aardio 源碼:
可以看到源碼中是如下啟動 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 范例的運行效果:
上面示例程序的主窗口是使用 win.ui.tabs 做的,只有其中一個標簽頁用到了網頁。
其實一般桌面軟件的界面并不是一定要全部使用網頁實現。有時候我們將界面中適合用網頁呈現的部分用網頁做,可能會更好。
我們在使用任何技術時,都要考慮一下適不適合。沒有一樣技術能適合做所有的事,多個選擇總是好事。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。