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

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

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

Dec 30, 2024 am 09:50 AM

各位程式設計師,大家好!在這個簡短系列的第一部分中,我們看到了桌面應用程式的建立和操作,用於儲存和加密使用 Wails 框架建立的密碼。我們還描述了 Go 後端以及如何將其綁定到前端。

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

事實是,我先使用Vanilla JsVue,然後使用React,甚至使用那個對許多人來說是React 的奇怪函式庫。 ??>HTMX(我必須說我喜歡??)。但是Svelte

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

但是讓我們進入正題吧。

I - 前端結構概覽


如果您使用過任何 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 腳本的原因,正如我已經告訴你的。我們也使用了TypeScript

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

但這個解釋中最重要的是wailsjs資料夾的內容。這就是Wails 所做的編譯發(fā)揮其魔力的地方。 go 子資料夾是儲存必須與前端互動的後端部分的「翻譯」為 Js/Ts
的方法的位置。例如,在 main/App.js(或其 TypeScript 版本 main/App.d.ts)中,有 App 結構的所有匯出(公共)方法:

...
.
├── 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 結構,或者相應的函數採用參數類型,則會有一個模組(models.ts,在本例中為類型,因為我們使用TypeScript),其中包含與Go對應的類別命名空間中的結構及其建構函數。

此外,runtime 子資料夾包含 Go 執(zhí)行時間套件中的所有方法,這些方法允許我們分別操作視窗以及從後端偵聽或發(fā)出的事件。

src 資料夾包含將由 Vite 編譯的文件,並將它們保存在「frontend/dist」中(並嵌入到最終的可執(zhí)行檔中),就像在任何 Web 應用程式中一樣。請注意,由於我們使用 Tailwindcss,style.css 包含基本的 Tailwind 配置以及我們需要使用的任何 CSS 類別。此外,作為介面使用網路技術的優(yōu)勢,我們可以輕鬆地使用一種或多種字體(資料夾資產/字體)或交換它們。

為了完成這個概述,請注意,當我們在開發(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 - 現在…深入研究 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>;

如你所見,我已經在 Svelte 中加入了 4 個 JavaScript 套件(除了已經提到的 Tailwindcss Daisyui):

  • svelte-copy,可以更輕鬆地將使用者名稱和密碼複製到剪貼簿。
  • svelte-i18n,用於 i18n 處理,即允許使用者更改應用程式的語言。
  • svelte-spa-router,Svelte 的一個小型路由庫,它可以更輕鬆地更改應用程式視窗中的視圖,因為在這種情況下,使用由SvelteKit。
  • sweetalert2,基本上用它來輕鬆快速地建立模態(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 產生的框架中的內容。 svelte-i18n 庫要求在main.js/ts 文件中註冊包含翻譯的JSON 文件,同時設定fallback/initial 語言(儘管我們'你會看到,稍後將根據使用者選擇的偏好進行操作)。包含翻譯的 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ā)現這個函式庫的系統(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"
  }
...

您也可以使用像這樣的網站,它將幫助您將 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 的公共方法(請參閱本系列的第一部分)。該函數查詢資料庫,如果其中註冊了主密碼,它會認為使用者已經註冊(它會傳回一個包含布林值的承諾),要求他輸入所述密碼以允許他存取其餘內容的意見。如果資料庫中沒有主密碼,則該使用者被視為“新”,要求他產生自己的密碼以首次進入應用程式。

最後,在安裝 Login.svelte 元件時,我們做了一些對應用程式的其餘部分很重要的事情。儘管 svelte-i18n 庫強制我們聲明初始語言代碼,但正如我們已經看到的,在安裝 Login.svelte 時,我們要求資料庫(使用 GetLanguage 綁定)檢查是否保存了語言代碼。如果資料庫傳回空字串,即沒有配置為使用者首選項的語言,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,綁定到獲取用戶輸入內容的輸入的狀態(tài),首先由onLogin 檢查它是否至少有6 個字符,並且它們都是ASCII 字符,即,通過這個小函數const isAscii = (str: string): boolean => 它們只有1 個位元組長(請參閱本系列第一部分的原因)。 /^[x00-x7F] $/.test(str);.如果檢查失敗,函數將傳回並向使用者顯示警告 toast。之後,如果資料庫中沒有保存主密碼(isLogin = false),則SaveMasterPassword 函數將保存使用者輸入的任何內容(Wails 產生的綁定);如果Promise 成功解析(傳回uuid 字串作為資料庫中儲存的記錄的Id),使用者將被svelte-spa-router 帶到主頁視圖庫的推送方法。相反,如果密碼通過了長度檢查,且不存在非ASCII 字符,且資料庫中存在主密碼(isLogin = true),則CheckMasterPassword 函數將根據儲存的密碼驗證其身份,或將使用者帶到主視圖(promise 為true 解決)或顯示toast 表示輸入的密碼不正確。

應用程式的中心視圖,同時也是最複雜的視圖是主頁視圖。它的HTML 實際上分為3 個元件:一個帶有搜尋輸入的頂部按鈕列(TopActions 元件)、一個底部按鈕欄(BottomActions 元件)以及一個中心區(qū)域,其中使用以下命令顯示已儲存密碼條目的總數或這些項目的清單:可捲動視窗(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([]);)。當根據使用者的請求安裝該元件時,後端會被要求提供已儲存密碼條目的完整清單。如果沒有搜尋字詞,則將其儲存在狀態(tài)中;如果有,則對獲得的陣列進行簡單過濾,並將其保存在狀態(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}`)}。基本上,我們呼叫路由庫的 Push 方法將使用者帶到詳細資訊視圖,但傳遞與相關項目相對應的 Id 參數。

使用者可以執(zhí)行的另一個操作是從清單中刪除項目。如果他單擊相應的按鈕,將顯示一個確認彈出窗口,並呼叫 showAlert 函數。函數依序呼叫 showWarning,它實際上是 sweetalert2 函式庫的抽象層(呼叫 sweetalert2 函式庫的所有函數都在 frontend/src/lib/popups/popups.ts 中)。如果使用者確認刪除操作,則呼叫DeleteEntry綁定(將其從資料庫中刪除),反過來,如果它傳回的promise得到解析,則呼叫deleteItem(將其從儲存在條目狀態(tài)的陣列中刪除) :

/* 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 視圖類似。兩者都不允許使用者在文字輸入的開頭和結尾輸入空格,並遵循與登入視圖相同的策略,要求密碼長度至少為 6 個 ASCII 字元?;旧希鼈兊呐c眾不同之處在於它們調用與需要執(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 事件中,它接收一個函數 (handleChange),該函數執(zhí)行 3 件事:

  • 使用 svelte-i18n 函式庫設定前端語言
  • 發(fā)出一個事件(“change_titles”),以便Wails運行時更改應用程式標題列的標題以及相關的選擇目錄選擇檔案對話框的標題到上一個操作
  • 將使用者選擇的語言保存在資料庫中,以便下次啟動應用程式時,它將開啟配置為該語言的。

傳回「設定」視圖,其整個操作由一系列傳送到後端或從後端接收的事件控制。最簡單的是退出按鈕:當使用者點擊它時,會在後端觸發(fā)並偵聽退出事件,然後應用程式關閉(onclick={() => EventsEmit("quit")})。 提示 通知使用者 Escape 鍵(快速鍵)執(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

...

如果使用者接受該操作,則會呼叫Drop 綁定,這會清除資料庫中的所有collections,如果它傳回的Promise 已解析,則會將使用者傳送至Login 視圖,顯示指示操作成功的模式。

剩下的另外兩個操作彼此類似,所以讓我們看看導入資料。

如果使用者點擊對應的按鈕,則會發(fā)出事件(onclick={() => EventsEmit("import_data")}),該事件在後端監(jiān)聽。收到後,將開啟本機選擇檔案對話方塊以允許使用者選擇備份檔案。如果使用者選擇文件,包含路徑(fileLocation)的變數將不包含空字串,這將在後端觸發(fā)一個事件(“enter_password”),該事件現在在前端偵聽,然後顯示新的彈出視窗詢問匯出時使用的主密碼。同樣,前端將發(fā)出另一個事件(「密碼」),其中攜帶使用者輸入的主密碼。當後端接收到這個新事件時,會執(zhí)行 Db 套件的 ImportDump 方法,該方法執(zhí)行從使用者選擇的備份檔案中讀取和還原 DB 中的資料的工作。結果,發(fā)出一個新事件(“imported_data”),該事件將其執(zhí)行結果(成功或不成功)作為附加資料攜帶。前端收到事件後只需執(zhí)行 2 個任務:

  • 如果結果成功,請設定備份檔案中儲存的語言並顯示指示操作成功的模式
  • 如果由於某種原因無法完成匯入,請顯示錯誤及其原因。

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

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

// 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 一樣。然而,應該說,正如我們所看到的,該視圖顯示了指向應用程式儲存庫的連結。顯然,在普通網頁中,錨標記() 將使我們導航到相應的鏈接,但在桌面應用程式中,如果Wails 在運行時沒有為此提供特定函數(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 文件。

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

make create-bundles 指令為Linux 版本建立一個.tar.xz 壓縮文件,其中包含應用程式和一個充當安裝執(zhí)行檔的「安裝程式」的Makefile,一個用於在開始功能表以及對應的應用程式圖示。對於 Windows 版本,二進位檔案只是在名為 dist/ 的資料夾中壓縮為 .zip。但是,如果您喜歡跨平臺自動構建,Wails 有一個 Github Actions,允許您上傳(預設選項)生成的工件到您的儲存庫。

請注意,如果您在運行時使用make create-bundles 命令,它將呼叫Wails 命令wails build -clean -upx (對於Linux)或wails build -skipbindings -s -platform windows/amd64 - upx(對於Windows )。 -upx 標誌是指使用您應該安裝在電腦上的

UPX 實用程式來壓縮二進位檔案??蓤?zhí)行檔案體積小的部分秘密是由於該實用程式所做的出色的壓縮工作。

最後,請注意,建置腳本會自動將目前儲存庫標籤新增至「關於」視圖,並在建置後將其值還原為預設值 (DEV_VERSION)。

??!這兩篇文章比我想像的還要長!但我希望您喜歡它們,最重要的是,它們可以幫助您思考新專案。在程式設計中學習一些東西就像這樣...

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

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

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

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發(fā)現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創(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

視覺化網頁開發(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)境中需權衡取捨。

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

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

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

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

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

如何在GO中的結構實例上調用方法? 如何在GO中的結構實例上調用方法? Jun 24, 2025 pm 03:17 PM

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

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

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

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

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

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

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

See all articles