国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

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

極簡密碼管理器桌面應用程序:進軍 Golang 的 Wails 框架(第 2 部分)

Dec 30, 2024 am 09:50 AM

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

在這一部分中,我們將處理用戶界面。正如我們在那篇文章中所述,Wails 允許我們使用任何我們喜歡的 Web 框架,甚至 Vanilla JS,來構建我們的 GUI。正如我所說,Wails 的創(chuàng)作者似乎偏愛 Svelte,因為他們總是將其作為首選。當我們要求使用 Svelte Typescript (wails init -n myproject -t svelte-ts) 創(chuàng)建項目時,Wails CLI(當前版本)會使用 Svelte3 生成腳手架。正如我已經(jīng)告訴過您的,如果您更喜歡使用 Svelte5(及其新功能),我有一個 bash 腳本可以自動創(chuàng)建它(無論如何,您必須安裝 Wails CLI)。此外,它還添加了 Taildwindcss Daisyui,這在我看來是界面設計的完美組合。

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

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

但是讓我們進入正題吧。

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


如果您使用過任何 Web 框架,您很快就會認識到 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 框架,您不會對其配置文件感到驚訝。這里我使用 Svelte5 (加上 Taildwindcss Daisyui 的配置),這就是生成我自己的 bash 腳本的原因,正如我已經(jīng)告訴過你的。我們還使用了TypeScript

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

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

...
.
├── 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

...

他們都返回一個承諾。如果 Promise“包裝”了一些用作返回類型的 Go 結(jié)構,或者相應的函數(shù)采用參數(shù)類型,則會有一個模塊(models.ts,在本例中為類型,因為我們使用 TypeScript),其中包含與 Go 對應的類命名空間中的結(jié)構及其構造函數(shù)。

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

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

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

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 個 JavaScript 包(除了已經(jīng)提到的 Tailwindcss Daisyui):

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

每個 SPA 的入口點都是 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 文件中注冊包含翻譯的 JSON 文件,同時設置 fallback/initial 語言(盡管我們'你會看到,稍后將根據(jù)用戶選擇的偏好進行操作)。包含翻譯的 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)這個庫的系統(tǒng)對于促進 Svelte 應用程序的翻譯非常簡單和方便(您可以查閱其文檔以了解更多詳細信息):

/* 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 文件翻譯成不同的語言。然而,問題是,當您使用 $format 填充 .svelte 文件時,您必須手動跟蹤它們,這是乏味且容易出錯的。我不知道有什么方法可以自動完成這項任務,如果有人知道,我會很感興趣,如果你能讓我知道?...否則,我必須想出某種腳本來完成這項工作。

與任何 Svelte 應用程序一樣,構建界面的下一步是 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,它是編譯應用程序時自動生成的 綁定,并被聲明為 struct App 的公共方法(請參閱本系列的第一部分)。該函數(shù)查詢數(shù)據(jù)庫,如果其中注冊了主密碼,它會認為用戶已經(jīng)注冊(它返回一個包含布爾值的承諾),要求他輸入所述密碼以允許他訪問其余內(nèi)容的意見。如果數(shù)據(jù)庫中沒有主密碼,則該用戶被視為“新”,要求他生成自己的密碼以首次進入應用程序。

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

/* 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

...

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

應用程序的中心視圖,同時也是最復雜的視圖是主頁視圖。它的 HTML 實際上分為 3 個組件:一個帶有搜索輸入的頂部按鈕欄(TopActions 組件)、一個底部按鈕欄(BottomActions 組件)以及一個中心區(qū)域,其中使用以下命令顯示已保存密碼條目的總數(shù)或這些條目的列表:可滾動窗口(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)成為一個空字符串,這樣如果有任何搜索詞,它就會被重置,從而顯示整個列表。另一方面,它切換 showList 狀態(tài)(props TopActions 中的 isEntriesList),以便父組件顯示或隱藏列表。

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

顯示完整列表或按用戶輸入的搜索詞過濾的列表的主要邏輯按預期由 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 個 props(listCounter 和 search)并維護一個狀態(tài)(讓條目:models.PasswordEntry[] = $state([]);)。當根據(jù)用戶的請求安裝該組件時,后端會被要求提供已保存密碼條目的完整列表。如果沒有搜索詞,則將其存儲在狀態(tài)中;如果有,則對獲得的數(shù)組進行簡單過濾,并將其保存在狀態(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 個操作。第一個是顯示條目的詳細信息,當他點擊相應的按鈕時執(zhí)行:onclick={() =>推送(`/details/${entry.Id}`)}?;旧?,我們調(diào)用路由庫的 Push 方法將用戶帶到詳細信息視圖,但傳遞與相關項目相對應的 Id 參數(shù)。

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

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

AddPassword 和 EditPassword 視圖的邏輯非常相似,也與 Login 視圖類似。兩者都不允許用戶在文本輸入的開頭和結(jié)尾輸入空格,并遵循與登錄視圖相同的策略,要求密碼長度至少為 6 個 ASCII 字符?;旧?,它們的與眾不同之處在于它們調(diào)用與需要執(zhí)行的操作相關的由 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

另一個有點復雜的視圖是“設置”。它有一個語言組件,它從其父組件(設置)接收 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 是一個處理用戶語言選擇的 select。在其 onchange 事件中,它接收一個函數(shù) (handleChange),該函數(shù)執(zhí)行 3 件事:

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

返回“設置”視圖,其整個操作由一系列發(fā)送到后端或從后端接收的事件控制。最簡單的是退出按鈕:當用戶單擊它時,會在后端觸發(fā)并偵聽退出事件,然后應用程序關閉(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

...

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

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

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

  • 如果結(jié)果成功,請設置備份文件中保存的語言并顯示指示操作成功的模式
  • 如果由于某種原因無法完成導入,請顯示錯誤及其原因。

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

...
.
├── 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 運行時函數(shù) (EventsOn) 返回一個函數(shù),該函數(shù)在調(diào)用時會取消所述偵聽器。當組件被銷毀時,取消所述監(jiān)聽器是很方便的。與 React 類似,onMount 鉤子可以通過讓監(jiān)聽器返回一個清理函數(shù)來“清理”它們,在這種情況下,該函數(shù)將調(diào)用 EventsOn 返回的所有函數(shù),我們已采取預防措施將其保存在單獨的文件中。變量:

// 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>;

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

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

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

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

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

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

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

最后,請注意,構建腳本會自動將當前存儲庫標簽添加到“關于”視圖,并在構建后將其值恢復為默認值 (DEV_VERSION)。

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

請記住,您可以在此 GitHub 存儲庫中找到所有應用程序代碼。

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

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

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

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Clothoff.io

Clothoff.io

AI脫衣機

Video Face Swap

Video Face Swap

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

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

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

Dreamweaver CS6

Dreamweaver CS6

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

SublimeText3 Mac版

SublimeText3 Mac版

神級代碼編輯軟件(SublimeText3)

默認情況下,GO靜態(tài)鏈接的含義是什么? 默認情況下,GO靜態(tài)鏈接的含義是什么? Jun 19, 2025 am 01:08 AM

Go默認將程序編譯為獨立二進制文件,主要原因是靜態(tài)鏈接。1.部署更簡單:無需額外安裝依賴庫,可直接跨Linux發(fā)行版運行;2.二進制體積更大:包含所有依賴導致文件尺寸增加,但可通過構建標志或壓縮工具優(yōu)化;3.更高的可預測性與安全性:避免外部庫版本變化帶來的風險,增強穩(wěn)定性;4.運行靈活性受限:無法熱更新共享庫,需重新編譯部署以修復依賴漏洞。這些特性使Go適用于CLI工具、微服務等場景,但在存儲受限或依賴集中管理的環(huán)境中需權衡取舍。

在沒有C中的手動內(nèi)存管理的情況下,如何確保內(nèi)存安全性? 在沒有C中的手動內(nèi)存管理的情況下,如何確保內(nèi)存安全性? Jun 19, 2025 am 01:11 AM

Goensuresmemorysafetywithoutmanualmanagementthroughautomaticgarbagecollection,nopointerarithmetic,safeconcurrency,andruntimechecks.First,Go’sgarbagecollectorautomaticallyreclaimsunusedmemory,preventingleaksanddanglingpointers.Second,itdisallowspointe

如何在GO中創(chuàng)建緩沖頻道? (例如,make(chan int,10)) 如何在GO中創(chuàng)建緩沖頻道? (例如,make(chan int,10)) Jun 20, 2025 am 01:07 AM

在Go中創(chuàng)建緩沖通道只需在make函數(shù)中指定容量參數(shù)即可。緩沖通道允許發(fā)送操作在沒有接收者時暫存數(shù)據(jù),只要未超過指定容量,例如ch:=make(chanint,10)創(chuàng)建了一個可存儲最多10個整型值的緩沖通道;與無緩沖通道不同,發(fā)送數(shù)據(jù)時不會立即阻塞,而是將數(shù)據(jù)暫存于緩沖區(qū)中,直到被接收者取走;使用時需注意:1.容量設置應合理以避免內(nèi)存浪費或頻繁阻塞;2.需防止緩沖區(qū)無限堆積數(shù)據(jù)導致內(nèi)存問題;3.可用chanstruct{}類型傳遞信號以節(jié)省資源;常見場景包括控制并發(fā)數(shù)量、生產(chǎn)者-消費者模型及異

如何使用GO進行系統(tǒng)編程任務? 如何使用GO進行系統(tǒng)編程任務? Jun 19, 2025 am 01:10 AM

Go是系統(tǒng)編程的理想選擇,因為它結(jié)合了C等編譯型語言的性能與現(xiàn)代語言的易用性和安全性。1.文件與目錄操作方面,Go的os包支持創(chuàng)建、刪除、重命名及檢查文件和目錄是否存在,使用os.ReadFile可一行代碼讀取整個文件,適用于編寫備份腳本或日志處理工具;2.進程管理方面,通過os/exec包的exec.Command函數(shù)可執(zhí)行外部命令、捕獲輸出、設置環(huán)境變量、重定向輸入輸出流以及控制進程生命周期,適合用于自動化工具和部署腳本;3.網(wǎng)絡與并發(fā)方面,net包支持TCP/UDP編程、DNS查詢及原始套

如何在GO中的結(jié)構實例上調(diào)用方法? 如何在GO中的結(jié)構實例上調(diào)用方法? Jun 24, 2025 pm 03:17 PM

在Go語言中,調(diào)用結(jié)構體方法需先定義結(jié)構體和綁定接收者的方法,使用點號訪問。定義結(jié)構體Rectangle后,可通過值接收者或指針接收者聲明方法;1.使用值接收者如func(rRectangle)Area()int,通過rect.Area()直接調(diào)用;2.若需修改結(jié)構體,應使用指針接收者如func(r*Rectangle)SetWidth(...),Go會自動處理指針與值的轉(zhuǎn)換;3.嵌入結(jié)構體時,內(nèi)嵌結(jié)構體的方法會被提升,可直接通過外層結(jié)構體調(diào)用;4.Go無需強制使用getter/setter,字

GO中的接口是什么?如何定義它們? GO中的接口是什么?如何定義它們? Jun 22, 2025 pm 03:41 PM

在Go語言中,接口是一種定義行為而不指定實現(xiàn)方式的類型。接口由方法簽名組成,任何實現(xiàn)這些方法的類型都自動滿足該接口。例如,定義一個Speaker接口包含Speak()方法,則所有實現(xiàn)該方法的類型均可視為Speaker。接口適用于編寫通用函數(shù)、抽象實現(xiàn)細節(jié)和測試中使用mock對象。定義接口使用interface關鍵字并列出方法簽名,無需顯式聲明類型實現(xiàn)了接口。常見用例包括日志、格式化、不同數(shù)據(jù)庫或服務的抽象,以及通知系統(tǒng)等。例如,Dog和Robot類型均可實現(xiàn)Speak方法,并傳遞給同一個Anno

如何在GO中使用字符串軟件包中的字符串函數(shù)? (例如len(),strings.contains(),strings.index(),strings.replaceall()) 如何在GO中使用字符串軟件包中的字符串函數(shù)? (例如len(),strings.contains(),strings.index(),strings.replaceall()) Jun 20, 2025 am 01:06 AM

在Go語言中,字符串操作主要通過strings包和內(nèi)置函數(shù)實現(xiàn)。1.strings.Contains()用于判斷字符串是否包含子串,返回布爾值;2.strings.Index()可查找子串首次出現(xiàn)的位置,若不存在則返回-1;3.strings.ReplaceAll()能替換所有匹配的子串,還可通過strings.Replace()控制替換次數(shù);4.len()函數(shù)用于獲取字符串字節(jié)數(shù)長度,但處理Unicode時需注意字符與字節(jié)的區(qū)別。這些功能常用于數(shù)據(jù)過濾、文本解析及字符串處理等場景。

如何使用IO軟件包在GO中使用輸入和輸出流? 如何使用IO軟件包在GO中使用輸入和輸出流? Jun 20, 2025 am 11:25 AM

TheGoiopackageprovidesinterfaceslikeReaderandWritertohandleI/Ooperationsuniformlyacrosssources.1.io.Reader'sReadmethodenablesreadingfromvarioussourcessuchasfilesorHTTPresponses.2.io.Writer'sWritemethodfacilitateswritingtodestinationslikestandardoutpu

See all articles