亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

首頁 后端開發(fā) Golang 極簡(jiǎn)密碼管理器桌面應(yīng)用程序:進(jìn)軍 Golang 的 Wails 框架(第 2 部分)

極簡(jiǎn)密碼管理器桌面應(yīng)用程序:進(jìn)軍 Golang 的 Wails 框架(第 2 部分)

Dec 30, 2024 am 09:50 AM

各位程序員,大家好!在這個(gè)簡(jiǎn)短系列的第一部分中,我們看到了桌面應(yīng)用程序的創(chuàng)建和操作,用于存儲(chǔ)和加密使用 Wails 框架創(chuàng)建的密碼。我們還描述了 Go 后端以及如何將其綁定到前端。

在這一部分中,我們將處理用戶界面。正如我們?cè)谀瞧恼轮兴?,Wails 允許我們使用任何我們喜歡的 Web 框架,甚至 Vanilla JS,來構(gòu)建我們的 GUI。正如我所說,Wails 的創(chuàng)作者似乎偏愛 Svelte,因?yàn)樗麄兛偸菍⑵渥鳛槭走x。當(dāng)我們要求使用 Svelte Typescript (wails init -n myproject -t svelte-ts) 創(chuàng)建項(xiàng)目時(shí),Wails CLI(當(dāng)前版本)會(huì)使用 Svelte3 生成腳手架。正如我已經(jīng)告訴過您的,如果您更喜歡使用 Svelte5(及其新功能),我有一個(gè) bash 腳本可以自動(dòng)創(chuàng)建它(無論如何,您必須安裝 Wails CLI)。此外,它還添加了 Taildwindcss Daisyui,這在我看來是界面設(shè)計(jì)的完美組合。

事實(shí)是,我首先使用 Vanilla JsVue,然后使用 React,甚至使用那個(gè)對(duì)于許多人來說是React 的奇怪庫。 ??>HTMX(我不得不說我喜歡??)。但是Svelte

讓你從一開始就愛上它,我不得不說,我是在嘗試Wails時(shí)第一次使用它的(我保證會(huì)繼續(xù)使用它......)。但是,盡管 Web 框架很舒服,但我們必須提醒后端開發(fā)人員,前端并不那么容易???!

但是讓我們進(jìn)入正題吧。

I - 前端結(jié)構(gòu)概覽


如果您使用過任何 Web 框架,您很快就會(huì)認(rèn)識(shí)到 Wails CLI 在底層使用了 ViteJ:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

如果您使用過 Vite 生成的任何 Web 框架,您不會(huì)對(duì)其配置文件感到驚訝。這里我使用 Svelte5 (加上 Taildwindcss Daisyui 的配置),這就是生成我自己的 bash 腳本的原因,正如我已經(jīng)告訴過你的。我們還使用了TypeScript

,這樣會(huì)方便前端的開發(fā),所以你也可以看到它的配置。

但是這個(gè)解釋中最重要的是wailsjs文件夾的內(nèi)容。這就是Wails 所做的編譯發(fā)揮其魔力的地方。 go 子文件夾是存儲(chǔ)必須與前端交互的后端部分的“翻譯”為 Js/Ts
的方法的位置。例如,在 main/App.js(或其 TypeScript 版本 main/App.d.ts)中,有 App 結(jié)構(gòu)的所有導(dǎo)出(公共)方法:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

他們都返回一個(gè)承諾。如果 Promise“包裝”了一些用作返回類型的 Go 結(jié)構(gòu),或者相應(yīng)的函數(shù)采用參數(shù)類型,則會(huì)有一個(gè)模塊(models.ts,在本例中為類型,因?yàn)槲覀兪褂?TypeScript),其中包含與 Go 對(duì)應(yīng)的類命名空間中的結(jié)構(gòu)及其構(gòu)造函數(shù)。

此外,runtime 子文件夾包含 Go 運(yùn)行時(shí)包中的所有方法,這些方法允許我們分別操作窗口以及從后端偵聽或發(fā)出的事件。

src 文件夾包含將由 Vite 編譯的文件,并將它們保存在“frontend/dist”中(并嵌入到最終的可執(zhí)行文件中),就像在任何 Web 應(yīng)用程序中一樣。請(qǐng)注意,由于我們使用 Tailwindcss,因此 style.css 包含基本的 Tailwind 配置以及我們需要使用的任何 CSS 類。此外,作為界面使用網(wǎng)絡(luò)技術(shù)的一個(gè)優(yōu)勢(shì),我們可以輕松地使用一種或多種字體(文件夾資產(chǎn)/字體)或交換它們。

為了完成這個(gè)概述,請(qǐng)注意,當(dāng)我們?cè)陂_發(fā)模式(wails dev)下編譯時(shí),除了允許我們熱重載之外,我們不僅可以觀察所做的更改(無論是在后端還是在前端)應(yīng)用程序窗口本身,而且還通過地址 http://localhost:34115 在 Web 瀏覽器中,因?yàn)?Web 服務(wù)器已啟動(dòng)。這允許您使用您最喜歡的瀏覽器開發(fā)擴(kuò)展。雖然必須說Wails本人為我們提供了一些非常有用的開發(fā)工具,但是當(dāng)我們右鍵單擊應(yīng)用程序窗口(僅在開發(fā)模式下)并選擇“Inspect Element”時(shí):

A minimalist password manager desktop app: a foray into Golang

II - 現(xiàn)在……深入研究 HTML、CSS 和 JavaScript?


// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH ? MODIWL
// This file is automatically generated. DO NOT EDIT
import {models} from '../models';

export function AddPasswordEntry(arg1:string,arg2:string,arg3:string):Promise<string>;

export function CheckMasterPassword(arg1:string):Promise<boolean>;

export function DeleteEntry(arg1:string):Promise<void>;

export function Drop():Promise<void>;

export function GetAllEntries():Promise<Array<models.PasswordEntry>>;

export function GetEntryById(arg1:string):Promise<models.PasswordEntry>;

export function GetLanguage():Promise<string>;

export function GetMasterPassword():Promise<boolean>;

export function GetPasswordCount():Promise<number>;

export function SaveLanguage(arg1:string):Promise<void>;

export function SaveMasterPassword(arg1:string):Promise<string>;

export function UpdateEntry(arg1:models.PasswordEntry):Promise<boolean>;

如你所見,我已經(jīng)向 Svelte 添加了 4 個(gè) JavaScript 包(除了已經(jīng)提到的 Tailwindcss Daisyui):

  • svelte-copy,可以更輕松地將用戶名和密碼復(fù)制到剪貼板。
  • svelte-i18n,用于 i18n 處理,即允許用戶更改應(yīng)用程序的語言。
  • svelte-spa-router,Svelte 的一個(gè)小型路由庫,它可以更輕松地更改應(yīng)用程序窗口中的視圖,因?yàn)樵谶@種情況下,使用由SvelteKit。
  • sweetalert2,基本上用它來輕松快速地創(chuàng)建模態(tài)框/對(duì)話框。

每個(gè) SPA 的入口點(diǎn)都是 main.js(或 main.ts)文件,所以讓我們從它開始:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

我突出顯示了添加到由 Wails CLI 生成的框架中的內(nèi)容。 svelte-i18n 庫要求在 main.js/ts 文件中注冊(cè)包含翻譯的 JSON 文件,同時(shí)設(shè)置 fallback/initial 語言(盡管我們'你會(huì)看到,稍后將根據(jù)用戶選擇的偏好進(jìn)行操作)。包含翻譯的 JSON 文件的格式為:

// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH ? MODIWL
// This file is automatically generated. DO NOT EDIT
import {models} from '../models';

export function AddPasswordEntry(arg1:string,arg2:string,arg3:string):Promise<string>;

export function CheckMasterPassword(arg1:string):Promise<boolean>;

export function DeleteEntry(arg1:string):Promise<void>;

export function Drop():Promise<void>;

export function GetAllEntries():Promise<Array<models.PasswordEntry>>;

export function GetEntryById(arg1:string):Promise<models.PasswordEntry>;

export function GetLanguage():Promise<string>;

export function GetMasterPassword():Promise<boolean>;

export function GetPasswordCount():Promise<number>;

export function SaveLanguage(arg1:string):Promise<void>;

export function SaveMasterPassword(arg1:string):Promise<string>;

export function UpdateEntry(arg1:models.PasswordEntry):Promise<boolean>;

我發(fā)現(xiàn)這個(gè)庫的系統(tǒng)對(duì)于促進(jìn) Svelte 應(yīng)用程序的翻譯非常簡(jiǎn)單和方便(您可以查閱其文檔以了解更多詳細(xì)信息):

/* package.json */
...
},
  "dependencies": {
    "svelte-copy": "^2.0.0",
    "svelte-i18n": "^4.0.1",
    "svelte-spa-router": "^4.0.1",
    "sweetalert2": "^11.14.5"
  }
...

您還可以使用像這樣的網(wǎng)站,它將幫助您將 JSON 文件翻譯成不同的語言。然而,問題是,當(dāng)您使用 $format 填充 .svelte 文件時(shí),您必須手動(dòng)跟蹤它們,這是乏味且容易出錯(cuò)的。我不知道有什么方法可以自動(dòng)完成這項(xiàng)任務(wù),如果有人知道,我會(huì)很感興趣,如果你能讓我知道?...否則,我必須想出某種腳本來完成這項(xiàng)工作。

與任何 Svelte 應(yīng)用程序一樣,構(gòu)建界面的下一步是 App.svelte 文件:

/* main.ts */

import { mount } from 'svelte'
import './style.css'
import App from './App.svelte'
import { addMessages, init } from "svelte-i18n"; // ? ?
import en from './locales/en.json'; // ? ?
import es from './locales/es.json'; // ? ?

addMessages('en', en); // ? ?
addMessages('es', es); // ? ?

init({
  fallbackLocale: 'en', // ? ?
  initialLocale: 'en', // ? ?
});

const app = mount(App, {
  target: document.getElementById('app')!,
})

export default app

這里我們使用 GetMasterPassword,它是編譯應(yīng)用程序時(shí)自動(dòng)生成的 綁定,并被聲明為 struct App 的公共方法(請(qǐng)參閱本系列的第一部分)。該函數(shù)查詢數(shù)據(jù)庫,如果其中注冊(cè)了主密碼,它會(huì)認(rèn)為用戶已經(jīng)注冊(cè)(它返回一個(gè)包含布爾值的承諾),要求他輸入所述密碼以允許他訪問其余內(nèi)容的意見。如果數(shù)據(jù)庫中沒有主密碼,則該用戶被視為“新”,要求他生成自己的密碼以首次進(jìn)入應(yīng)用程序。

最后,在安裝 Login.svelte 組件時(shí),我們做了一些對(duì)應(yīng)用程序的其余部分很重要的事情。盡管 svelte-i18n 庫強(qiáng)制我們聲明初始語言代碼,但正如我們已經(jīng)看到的,在安裝 Login.svelte 時(shí),我們要求數(shù)據(jù)庫(使用 GetLanguage 綁定)檢查是否保存了語言代碼。如果數(shù)據(jù)庫返回空字符串,即沒有配置為用戶首選項(xiàng)的語言,svelte-i18n 將使用配置為initialLocale 的值。如果配置了一種語言,則將設(shè)置該語言 (locale.set(result);) 并發(fā)出“change_titles”事件,標(biāo)題欄和應(yīng)用程序本機(jī)對(duì)話框的翻譯標(biāo)題將傳遞到該事件供后端處理:

/* frontend/src/locales/en.json */

{
    "language": "Language",
    "app_title": "Nu-i uita ? minimalist password store",
    "select_directory": "Select the directory where to save the data export",
    "select_file": "Select the backup file to import",
    "master_password": "Master Password ?",
    "generate": "Generate",
    "insert": "Insert",
    "login": "Login",
    ...
}


/* frontend/src/locales/es.json */

{
    "language": "Idioma",
    "app_title": "Nu-i uita ? almacén de contrase?as minimalista",
    "select_directory": "Selecciona el directorio donde guardar los datos exportados",
    "select_file": "Selecciona el archivo de respaldo que deseas importar",
    "master_password": "Contrase?a Maestra ?",
    "generate": "Generar",
    "insert": "Insertar",
    "login": "Inciar sesión",
    ...
}

以下是處理登錄的邏輯:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

簡(jiǎn)單地說:newPassword,綁定到獲取用戶輸入內(nèi)容的輸入的狀態(tài),首先由 onLogin 檢查它是否至少有 6 個(gè)字符,并且它們都是 ASCII 字符,即,通過這個(gè)小函數(shù) const isAscii = (str: string): boolean => 它們只有 1 個(gè)字節(jié)長(請(qǐng)參閱本系列第一部分中的原因)。 /^[x00-x7F] $/.test(str);.如果檢查失敗,該函數(shù)將返回并向用戶顯示警告 toast。之后,如果數(shù)據(jù)庫中沒有保存主密碼(isLogin = false),則 SaveMasterPassword 函數(shù)將保存用戶輸入的任何內(nèi)容(Wails 生成的綁定);如果 Promise 成功解析(返回 uuid 字符串作為數(shù)據(jù)庫中存儲(chǔ)的記錄的 Id),用戶將被 svelte-spa-router 帶到主頁視圖庫的推送方法。相反,如果密碼通過了長度檢查,且不存在 非 ASCII 字符,并且數(shù)據(jù)庫中存在主密碼 (isLogin = true),則 CheckMasterPassword 函數(shù)將根據(jù)存儲(chǔ)的密碼驗(yàn)證其身份,或者將用戶帶到主視圖(promise 為 true 解決)或顯示 toast 表明輸入的密碼不正確。

應(yīng)用程序的中心視圖,同時(shí)也是最復(fù)雜的視圖是主頁視圖。它的 HTML 實(shí)際上分為 3 個(gè)組件:一個(gè)帶有搜索輸入的頂部按鈕欄(TopActions 組件)、一個(gè)底部按鈕欄(BottomActions 組件)以及一個(gè)中心區(qū)域,其中使用以下命令顯示已保存密碼條目的總數(shù)或這些條目的列表:可滾動(dòng)窗口(EntriesList 組件):

// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH ? MODIWL
// This file is automatically generated. DO NOT EDIT
import {models} from '../models';

export function AddPasswordEntry(arg1:string,arg2:string,arg3:string):Promise<string>;

export function CheckMasterPassword(arg1:string):Promise<boolean>;

export function DeleteEntry(arg1:string):Promise<void>;

export function Drop():Promise<void>;

export function GetAllEntries():Promise<Array<models.PasswordEntry>>;

export function GetEntryById(arg1:string):Promise<models.PasswordEntry>;

export function GetLanguage():Promise<string>;

export function GetMasterPassword():Promise<boolean>;

export function GetPasswordCount():Promise<number>;

export function SaveLanguage(arg1:string):Promise<void>;

export function SaveMasterPassword(arg1:string):Promise<string>;

export function UpdateEntry(arg1:models.PasswordEntry):Promise<boolean>;

也就是說,它使搜索狀態(tài)(searchTerms)成為一個(gè)空字符串,這樣如果有任何搜索詞,它就會(huì)被重置,從而顯示整個(gè)列表。另一方面,它切換 showList 狀態(tài)(props TopActions 中的 isEntriesList),以便父組件顯示或隱藏列表。

正如我們?cè)谏蠄D中看到的,兩個(gè)子組件與父組件的 searchTerms 狀態(tài)共享相同的 props。 TopActions 組件捕獲用戶的輸入,并將其作為狀態(tài)傳遞給父組件 Home,而父組件 Home 又將其作為 props 傳遞給其子組件 EntriesList。

顯示完整列表或按用戶輸入的搜索詞過濾的列表的主要邏輯按預(yù)期由 EntriesList 組件執(zhí)行:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

正如我們所說,收到 2 個(gè) props(listCounter 和 search)并維護(hù)一個(gè)狀態(tài)(讓條目:models.PasswordEntry[] = $state([]);)。當(dāng)根據(jù)用戶的請(qǐng)求安裝該組件時(shí),后端會(huì)被要求提供已保存密碼條目的完整列表。如果沒有搜索詞,則將其存儲(chǔ)在狀態(tài)中;如果有,則對(duì)獲得的數(shù)組進(jìn)行簡(jiǎn)單過濾,并將其保存在狀態(tài):

// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH ? MODIWL
// This file is automatically generated. DO NOT EDIT
import {models} from '../models';

export function AddPasswordEntry(arg1:string,arg2:string,arg3:string):Promise<string>;

export function CheckMasterPassword(arg1:string):Promise<boolean>;

export function DeleteEntry(arg1:string):Promise<void>;

export function Drop():Promise<void>;

export function GetAllEntries():Promise<Array<models.PasswordEntry>>;

export function GetEntryById(arg1:string):Promise<models.PasswordEntry>;

export function GetLanguage():Promise<string>;

export function GetMasterPassword():Promise<boolean>;

export function GetPasswordCount():Promise<number>;

export function SaveLanguage(arg1:string):Promise<void>;

export function SaveMasterPassword(arg1:string):Promise<string>;

export function UpdateEntry(arg1:models.PasswordEntry):Promise<boolean>;

在顯示的列表中,用戶可以執(zhí)行 2 個(gè)操作。第一個(gè)是顯示條目的詳細(xì)信息,當(dāng)他點(diǎn)擊相應(yīng)的按鈕時(shí)執(zhí)行:onclick={() =>推送(`/details/${entry.Id}`)}?;旧?,我們調(diào)用路由庫的 Push 方法將用戶帶到詳細(xì)信息視圖,但傳遞與相關(guān)項(xiàng)目相對(duì)應(yīng)的 Id 參數(shù)。

用戶可以執(zhí)行的另一個(gè)操作是從列表中刪除項(xiàng)目。如果他單擊相應(yīng)的按鈕,將顯示一個(gè)確認(rèn)彈出窗口,調(diào)用 showAlert 函數(shù)。該函數(shù)依次調(diào)用 showWarning,它實(shí)際上是 sweetalert2 庫的抽象層(調(diào)用 sweetalert2 庫的所有函數(shù)都在 frontend/src/lib/popups/popups.ts 中)。如果用戶確認(rèn)刪除操作,則調(diào)用DeleteEntry綁定(將其從數(shù)據(jù)庫中刪除),反過來,如果它返回的promise得到解析,則調(diào)用deleteItem(將其從存儲(chǔ)在條目狀態(tài)的數(shù)組中刪除) :

/* package.json */
...
},
  "dependencies": {
    "svelte-copy": "^2.0.0",
    "svelte-i18n": "^4.0.1",
    "svelte-spa-router": "^4.0.1",
    "sweetalert2": "^11.14.5"
  }
...

主頁視圖的另一個(gè)組件(BottomActions)要簡(jiǎn)單得多:它不接收 props 并且僅限于將用戶重定向到各種視圖(Settings、About 或 AddPassword)。

AddPassword 和 EditPassword 視圖的邏輯非常相似,也與 Login 視圖類似。兩者都不允許用戶在文本輸入的開頭和結(jié)尾輸入空格,并遵循與登錄視圖相同的策略,要求密碼長度至少為 6 個(gè) ASCII 字符?;旧希鼈兊呐c眾不同之處在于它們調(diào)用與需要執(zhí)行的操作相關(guān)的由 Wails 生成的鏈接:

/* main.ts */

import { mount } from 'svelte'
import './style.css'
import App from './App.svelte'
import { addMessages, init } from "svelte-i18n"; // ? ?
import en from './locales/en.json'; // ? ?
import es from './locales/es.json'; // ? ?

addMessages('en', en); // ? ?
addMessages('es', es); // ? ?

init({
  fallbackLocale: 'en', // ? ?
  initialLocale: 'en', // ? ?
});

const app = mount(App, {
  target: document.getElementById('app')!,
})

export default app

另一個(gè)有點(diǎn)復(fù)雜的視圖是“設(shè)置”。它有一個(gè)語言組件,它從其父組件(設(shè)置)接收 props languageName:

/* frontend/src/locales/en.json */

{
    "language": "Language",
    "app_title": "Nu-i uita ? minimalist password store",
    "select_directory": "Select the directory where to save the data export",
    "select_file": "Select the backup file to import",
    "master_password": "Master Password ?",
    "generate": "Generate",
    "insert": "Insert",
    "login": "Login",
    ...
}


/* frontend/src/locales/es.json */

{
    "language": "Idioma",
    "app_title": "Nu-i uita ? almacén de contrase?as minimalista",
    "select_directory": "Selecciona el directorio donde guardar los datos exportados",
    "select_file": "Selecciona el archivo de respaldo que deseas importar",
    "master_password": "Contrase?a Maestra ?",
    "generate": "Generar",
    "insert": "Insertar",
    "login": "Inciar sesión",
    ...
}

此組件的 HTML 是一個(gè)處理用戶語言選擇的 select。在其 onchange 事件中,它接收一個(gè)函數(shù) (handleChange),該函數(shù)執(zhí)行 3 件事:

  • 使用 svelte-i18n 庫設(shè)置前端語言
  • 發(fā)出一個(gè)事件(“change_titles”),以便Wails運(yùn)行時(shí)更改應(yīng)用程序標(biāo)題欄的標(biāo)題以及相關(guān)的選擇目錄選擇文件對(duì)話框的標(biāo)題到上一個(gè)操作
  • 將用戶選擇的語言保存在數(shù)據(jù)庫中,以便下次啟動(dòng)應(yīng)用程序時(shí),它將打開配置為該語言的。

返回“設(shè)置”視圖,其整個(gè)操作由一系列發(fā)送到后端或從后端接收的事件控制。最簡(jiǎn)單的是退出按鈕:當(dāng)用戶單擊它時(shí),會(huì)在后端觸發(fā)并偵聽退出事件,然后應(yīng)用程序關(guān)閉(onclick={() => EventsEmit("quit")})。 提示 通知用戶 Escape 鍵(快捷鍵)執(zhí)行相同的操作,正如我們已經(jīng)解釋過的。

重置按鈕調(diào)用顯示彈出窗口的函數(shù):

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

如果用戶接受該操作,則會(huì)調(diào)用 Drop 綁定,這會(huì)清除數(shù)據(jù)庫中的所有 collections,如果它返回的 Promise 得到解析,則會(huì)將用戶發(fā)送到 Login 視圖,顯示指示操作成功的模式。

剩下的另外兩個(gè)操作彼此類似,所以讓我們看看導(dǎo)入數(shù)據(jù)。

如果用戶點(diǎn)擊相應(yīng)的按鈕,則會(huì)發(fā)出一個(gè)事件(onclick={() => EventsEmit("import_data")}),該事件在后端監(jiān)聽。收到后,將打開本機(jī)選擇文件對(duì)話框以允許用戶選擇備份文件。如果用戶選擇文件,包含路徑(fileLocation)的變量將不包含空字符串,這將在后端觸發(fā)一個(gè)事件(“enter_password”),該事件現(xiàn)在在前端偵聽,然后顯示一個(gè)新的彈出窗口詢問導(dǎo)出時(shí)使用的主密碼。同樣,前端將發(fā)出另一個(gè)事件(“密碼”),其中攜帶用戶輸入的主密碼。當(dāng)后端接收到這個(gè)新事件時(shí),會(huì)執(zhí)行 Db 包的 ImportDump 方法,該方法執(zhí)行從用戶選擇的備份文件中讀取和恢復(fù) DB 中的數(shù)據(jù)的工作。結(jié)果,發(fā)出一個(gè)新事件(“imported_data”),該事件將其執(zhí)行結(jié)果(成功或不成功)作為附加數(shù)據(jù)攜帶。前端收到事件后只需執(zhí)行 2 個(gè)任務(wù):

  • 如果結(jié)果成功,請(qǐng)?jiān)O(shè)置備份文件中保存的語言并顯示指示操作成功的模式
  • 如果由于某種原因無法完成導(dǎo)入,請(qǐng)顯示錯(cuò)誤及其原因。

所有這些在代碼邏輯中比用文字解釋要容易得多?:

...
.
├── index.html
├── package.json
├── package.json.md5
├── package-lock.json
├── postcss.config.js
├── README.md
├── src
│?? ├── App.svelte
│?? ├── assets
│?? │?? ├── fonts
│?? │?? │?? ├── nunito-v16-latin-regular.woff2
│?? │?? │?? └── OFL.txt
│?? │?? └── images
│?? │??     └── logo-universal.png
│?? ├── lib
│?? │?? ├── BackBtn.svelte
│?? │?? ├── BottomActions.svelte
│?? │?? ├── EditActions.svelte
│?? │?? ├── EntriesList.svelte
│?? │?? ├── Language.svelte
│?? │?? ├── popups
│?? │?? │?? ├── alert-icons.ts
│?? │?? │?? └── popups.ts
│?? │?? ├── ShowPasswordBtn.svelte
│?? │?? └── TopActions.svelte
│?? ├── locales
│?? │?? ├── en.json
│?? │?? └── es.json
│?? ├── main.ts
│?? ├── pages
│?? │?? ├── About.svelte
│?? │?? ├── AddPassword.svelte
│?? │?? ├── Details.svelte
│?? │?? ├── EditPassword.svelte
│?? │?? ├── Home.svelte
│?? │?? ├── Login.svelte
│?? │?? └── Settings.svelte
│?? ├── style.css
│?? └── vite-env.d.ts
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── wailsjs
    ├── go
    │?? ├── main
    │?? │?? ├── App.d.ts
    │?? │?? └── App.js
    │?? └── models.ts
    └── runtime
        ├── package.json
        ├── runtime.d.ts
        └── runtime.js

...

值得一提的是,在前端注冊(cè)偵聽器的 Wails 運(yùn)行時(shí)函數(shù) (EventsOn) 返回一個(gè)函數(shù),該函數(shù)在調(diào)用時(shí)會(huì)取消所述偵聽器。當(dāng)組件被銷毀時(shí),取消所述監(jiān)聽器是很方便的。與 React 類似,onMount 鉤子可以通過讓監(jiān)聽器返回一個(gè)清理函數(shù)來“清理”它們,在這種情況下,該函數(shù)將調(diào)用 EventsOn 返回的所有函數(shù),我們已采取預(yù)防措施將其保存在單獨(dú)的文件中。變量:

// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH ? MODIWL
// This file is automatically generated. DO NOT EDIT
import {models} from '../models';

export function AddPasswordEntry(arg1:string,arg2:string,arg3:string):Promise<string>;

export function CheckMasterPassword(arg1:string):Promise<boolean>;

export function DeleteEntry(arg1:string):Promise<void>;

export function Drop():Promise<void>;

export function GetAllEntries():Promise<Array<models.PasswordEntry>>;

export function GetEntryById(arg1:string):Promise<models.PasswordEntry>;

export function GetLanguage():Promise<string>;

export function GetMasterPassword():Promise<boolean>;

export function GetPasswordCount():Promise<number>;

export function SaveLanguage(arg1:string):Promise<void>;

export function SaveMasterPassword(arg1:string):Promise<string>;

export function UpdateEntry(arg1:models.PasswordEntry):Promise<boolean>;

為了完成對(duì)我們應(yīng)用程序前端部分的審查,只需介紹一下“關(guān)于”組件即可。這幾乎沒有邏輯,因?yàn)樗鼉H限于顯示有關(guān)應(yīng)用程序的信息,就像常見的 about 一樣。然而,應(yīng)該說,正如我們所看到的,該視圖顯示了指向應(yīng)用程序存儲(chǔ)庫的鏈接。顯然,在普通網(wǎng)頁中,錨標(biāo)記 () 將使我們導(dǎo)航到相應(yīng)的鏈接,但在桌面應(yīng)用程序中,如果 Wails 在運(yùn)行時(shí)沒有為此提供特定函數(shù) (BrowserOpenURL),則不會(huì)發(fā)生這種情況:

/* package.json */
...
},
  "dependencies": {
    "svelte-copy": "^2.0.0",
    "svelte-i18n": "^4.0.1",
    "svelte-spa-router": "^4.0.1",
    "sweetalert2": "^11.14.5"
  }
...

這會(huì)將二進(jìn)制文件構(gòu)建到 build/bin 文件夾中。但是,要選擇其他構(gòu)建選項(xiàng)或執(zhí)行交叉編譯,您可能需要查看 Wails CLI 文檔。

對(duì)于這個(gè)應(yīng)用程序,我想我已經(jīng)在本系列的第一部分中提到過,我只關(guān)注Windows和Linux的編譯。為了以舒適的方式執(zhí)行這些任務(wù)(由于測(cè)試,這些任務(wù)是重復(fù)的),我創(chuàng)建了一些小腳本和一個(gè)“協(xié)調(diào)”它們的 Makefile。

make create-bundles 命令為 Linux 版本創(chuàng)建一個(gè) .tar.xz 壓縮文件,其中包含應(yīng)用程序和一個(gè)充當(dāng)安裝可執(zhí)行文件的“安裝程序”的 Makefile,一個(gè)用于在 開始菜單以及相應(yīng)的應(yīng)用程序圖標(biāo)。對(duì)于 Windows 版本,二進(jìn)制文件只是在名為 dist/ 的文件夾中壓縮為 .zip。但是,如果您更喜歡跨平臺(tái)自動(dòng)構(gòu)建,Wails 有一個(gè) Github Actions,允許您上傳(默認(rèn)選項(xiàng))生成的工件到您的存儲(chǔ)庫。

請(qǐng)注意,如果您在運(yùn)行時(shí)使用 make create-bundles 命令,它將調(diào)用 Wails 命令 wails build -clean -upx (對(duì)于 Linux)或 wails build -skipbindings -s -platform windows/amd64 - upx(對(duì)于 Windows)。 -upx 標(biāo)志是指使用您應(yīng)該安裝在計(jì)算機(jī)上的

UPX 實(shí)用程序來壓縮二進(jìn)制文件??蓤?zhí)行文件體積小的部分秘密是由于該實(shí)用程序所做的出色的壓縮工作。

最后,請(qǐng)注意,構(gòu)建腳本會(huì)自動(dòng)將當(dāng)前存儲(chǔ)庫標(biāo)簽添加到“關(guān)于”視圖,并在構(gòu)建后將其值恢復(fù)為默認(rèn)值 (DEV_VERSION)。

?。∵@兩篇文章比我想象的要長!但我希望您喜歡它們,最重要的是,它們可以幫助您思考新項(xiàng)目。在編程中學(xué)習(xí)一些東西就像這樣......

請(qǐng)記住,您可以在此 GitHub 存儲(chǔ)庫中找到所有應(yīng)用程序代碼。

我相信我會(huì)在其他帖子中見到你。編碼愉快?!!

以上是極簡(jiǎn)密碼管理器桌面應(yīng)用程序:進(jìn)軍 Golang 的 Wails 框架(第 2 部分)的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)代碼編輯軟件(SublimeText3)

了解Web API的Golang和Python之間的性能差異 了解Web API的Golang和Python之間的性能差異 Jul 03, 2025 am 02:40 AM

Golangofferssuperiorperformance,nativeconcurrencyviagoroutines,andefficientresourceusage,makingitidealforhigh-traffic,low-latencyAPIs;2.Python,whileslowerduetointerpretationandtheGIL,provideseasierdevelopment,arichecosystem,andisbettersuitedforI/O-bo

是Golang前端還是后端 是Golang前端還是后端 Jul 08, 2025 am 01:44 AM

Golang主要用于后端開發(fā),但也能在前端領(lǐng)域間接發(fā)揮作用。其設(shè)計(jì)目標(biāo)聚焦高性能、并發(fā)處理和系統(tǒng)級(jí)編程,適合構(gòu)建API服務(wù)器、微服務(wù)、分布式系統(tǒng)、數(shù)據(jù)庫操作及CLI工具等后端應(yīng)用。雖然Golang不是網(wǎng)頁前端的主流語言,但可通過GopherJS編譯成JavaScript、通過TinyGo運(yùn)行于WebAssembly,或搭配模板引擎生成HTML頁面來參與前端開發(fā)。然而,現(xiàn)代前端開發(fā)仍需依賴JavaScript/TypeScript及其生態(tài)。因此,Golang更適合以高性能后端為核心的技術(shù)棧選擇。

如何安裝去 如何安裝去 Jul 09, 2025 am 02:37 AM

安裝Go的關(guān)鍵在于選擇正確版本、配置環(huán)境變量并驗(yàn)證安裝。1.前往官網(wǎng)下載對(duì)應(yīng)系統(tǒng)的安裝包,Windows使用.msi文件,macOS使用.pkg文件,Linux使用.tar.gz文件并解壓至/usr/local目錄;2.配置環(huán)境變量,在Linux/macOS中編輯~/.bashrc或~/.zshrc添加PATH和GOPATH,Windows則在系統(tǒng)屬性中設(shè)置PATH為Go的安裝路徑;3.使用goversion命令驗(yàn)證安裝,并運(yùn)行測(cè)試程序hello.go確認(rèn)編譯執(zhí)行正常。整個(gè)流程中PATH設(shè)置和環(huán)

如何在Golang中構(gòu)建GraphQl API 如何在Golang中構(gòu)建GraphQl API Jul 08, 2025 am 01:03 AM

要構(gòu)建一個(gè)GraphQLAPI在Go語言中,推薦使用gqlgen庫以提高開發(fā)效率。1.首先選擇合適的庫,如gqlgen,它支持根據(jù)schema自動(dòng)生成代碼;2.接著定義GraphQLschema,描述API的結(jié)構(gòu)和查詢?nèi)肟?,如定義Post類型和查詢方法;3.然后初始化項(xiàng)目并生成基礎(chǔ)代碼,實(shí)現(xiàn)resolver中的業(yè)務(wù)邏輯;4.最后將GraphQLhandler接入HTTPserver,通過內(nèi)置Playground測(cè)試API。注意事項(xiàng)包括字段命名規(guī)范、錯(cuò)誤處理、性能優(yōu)化及安全設(shè)置等,確保項(xiàng)目可維護(hù)性

典型Golang vs Python Web服務(wù)的資源消耗(CPU/內(nèi)存)基準(zhǔn) 典型Golang vs Python Web服務(wù)的資源消耗(CPU/內(nèi)存)基準(zhǔn) Jul 03, 2025 am 02:38 AM

Golang在構(gòu)建Web服務(wù)時(shí)CPU和內(nèi)存消耗通常低于Python。1.Golang的goroutine模型調(diào)度高效,并發(fā)請(qǐng)求處理能力強(qiáng),CPU使用率更低;2.Go編譯為原生代碼,運(yùn)行時(shí)不依賴虛擬機(jī),內(nèi)存占用更?。?.Python因GIL和解釋執(zhí)行機(jī)制,在并發(fā)場(chǎng)景下CPU和內(nèi)存開銷更大;4.雖然Python開發(fā)效率高、生態(tài)豐富,但資源消耗較高,適合并發(fā)要求不高的場(chǎng)景。

Go Sync.WaitGroup示例 Go Sync.WaitGroup示例 Jul 09, 2025 am 01:48 AM

sync.WaitGroup用于等待一組goroutine完成任務(wù),其核心是通過Add、Done、Wait三個(gè)方法協(xié)同工作。1.Add(n)設(shè)置需等待的goroutine數(shù)量;2.Done()在每個(gè)goroutine結(jié)束時(shí)調(diào)用,計(jì)數(shù)減一;3.Wait()阻塞主協(xié)程直到所有任務(wù)完成。使用時(shí)需注意:Add應(yīng)在goroutine外調(diào)用、避免重復(fù)Wait、務(wù)必確保Done被調(diào)用,推薦配合defer使用。常見于并發(fā)抓取網(wǎng)頁、批量數(shù)據(jù)處理等場(chǎng)景,能有效控制并發(fā)流程。

去嵌入軟件包教程 去嵌入軟件包教程 Jul 09, 2025 am 02:46 AM

使用Go的embed包可以方便地將靜態(tài)資源嵌入二進(jìn)制,適合Web服務(wù)打包HTML、CSS、圖片等文件。1.聲明嵌入資源需在變量前加//go:embed注釋,如嵌入單個(gè)文件hello.txt;2.可嵌入整個(gè)目錄如static/*,通過embed.FS實(shí)現(xiàn)多文件打包;3.開發(fā)時(shí)建議通過buildtag或環(huán)境變量切換磁盤加載模式以提高效率;4.注意路徑正確性、文件大小限制及嵌入資源的只讀特性。合理使用embed能簡(jiǎn)化部署并優(yōu)化項(xiàng)目結(jié)構(gòu)。

評(píng)估代碼的可讀性和可維護(hù)性:Golang vs Python觀點(diǎn) 評(píng)估代碼的可讀性和可維護(hù)性:Golang vs Python觀點(diǎn) Jul 03, 2025 am 02:40 AM

WhenchoosingbetweenGolangandPythonforcodereadabilityandmaintainability,thedecisionhingesonteampriorities.1.Golangoffersstrictconsistencywithminimal,opinionatedsyntaxandbuilt-intoolinglikegofmt,ensuringuniformcodestyleandearlyerrordetection.2.Pythonpr

See all articles