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

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

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

Dec 30, 2024 am 09:50 AM

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

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

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

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

但是讓我們進入正題吧。

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


如果您使用過任何 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 產(chǎn)生的任何 Web 框架,您不會對其設(shè)定檔感到驚訝。這裡我使用 Svelte5 (加上 Taildwindcss Daisyui 的配置),這就是產(chǎn)生我自己的 bash 腳本的原因,正如我已經(jīng)告訴你的。我們也使用了TypeScript

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

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

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

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

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

為了完成這個概述,請注意,當(dāng)我們在開發(fā)模式(wails dev)下編譯時,除了允許我們熱重載之外,我們不僅可以觀察所做的更改(無論是在後端還是在前端)應(yīng)用程式視窗本身,也透過位址http://localhost:34115 在Web 瀏覽器中,因為Web 伺服器已啟動。這允許您使用您最喜歡的瀏覽器開發(fā)擴充功能。雖然必須說Wails本人為我們提供了一些非常有用的開發(fā)工具,但是當(dāng)我們右鍵單擊應(yīng)用程式視窗(僅在開發(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 處理,即允許使用者更改應(yīng)用程式的語言。
  • svelte-spa-router,Svelte 的一個小型路由庫,它可以更輕鬆地更改應(yīng)用程式視窗中的視圖,因為在這種情況下,使用由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 產(chǎn)生的框架中的內(nèi)容。 svelte-i18n 庫要求在main.js/ts 文件中註冊包含翻譯的JSON 文件,同時設(shè)定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 應(yīng)用程式的翻譯非常簡單和方便(您可以查閱其文件以了解更多詳細資訊):

/* 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 檔案時,您必須手動追蹤它們,這是乏味且容易出錯的。我不知道有什麼方法可以自動完成這項任務(wù),如果有人知道,我會很感興趣,如果你能讓我知道? ……否則,我必須想出某種腳本來完成這項工作。

與任何 Svelte 應(yīng)用程式一樣,建立介面的下一步是 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)用程式時自動產(chǎn)生的 綁定,並被宣告為 struct App 的公共方法(請參閱本系列的第一部分)。該函數(shù)查詢資料庫,如果其中註冊了主密碼,它會認為使用者已經(jīng)註冊(它會傳回一個包含布林值的承諾),要求他輸入所述密碼以允許他存取其餘內(nèi)容的意見。如果資料庫中沒有主密碼,則該使用者被視為“新”,要求他產(chǎn)生自己的密碼以首次進入應(yīng)用程式。

最後,在安裝 Login.svelte 元件時,我們做了一些對應(yīng)用程式的其餘部分很重要的事情。儘管 svelte-i18n 庫強制我們聲明初始語言代碼,但正如我們已經(jīng)看到的,在安裝 Login.svelte 時,我們要求資料庫(使用 GetLanguage 綁定)檢查是否保存了語言代碼。如果資料庫傳回空字串,即沒有配置為使用者首選項的語言,svelte-i18n 將使用配置為initialLocale 的值。如果配置了一種語言,則將設(shè)定該語言(locale.set(result);) 並發(fā)出「change_titles」事件,標(biāo)題列和應(yīng)用程式本機對話方塊的翻譯標(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

...

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

應(yīng)用程式的中心視圖,同時也是最複雜的視圖是主頁視圖。它的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。

顯示完整清單或按使用者輸入的搜尋字詞過濾的清單的主要邏輯按預(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 個 props(listCounter 和 search)並維護一個狀態(tài)(讓條目:models.PasswordEntry[] = $state([]);)。當(dāng)根據(jù)使用者的請求安裝該元件時,後端會被要求提供已儲存密碼條目的完整清單。如果沒有搜尋字詞,則將其儲存在狀態(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 個操作。第一個是顯示條目的詳細信息,當(dāng)他點擊相應(yīng)的按鈕時執(zhí)行:onclick={() =>推送(`/details/${entry.Id}`)}?;旧?,我們呼叫路由庫的 Push 方法將使用者帶到詳細資訊視圖,但傳遞與相關(guān)項目相對應(yīng)的 Id 參數(shù)。

使用者可以執(zhí)行的另一個操作是從清單中刪除項目。如果他單擊相應(yīng)的按鈕,將顯示一個確認彈出窗口,並呼叫 showAlert 函數(shù)。函數(shù)依序呼叫 showWarning,它實際上是 sweetalert2 函式庫的抽象層(呼叫 sweetalert2 函式庫的所有函數(shù)都在 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 並且僅限於將使用者重新導(dǎo)向到各種視圖(Settings、About 或 AddPassword)。

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

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

另一個有點複雜的視圖是「設(shè)定」。它有一個語言元件,它從其父元件(設(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 是一個處理使用者語言選擇的 select。在其 onchange 事件中,它接收一個函數(shù) (handleChange),該函數(shù)執(zhí)行 3 件事:

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

傳回「設(shè)定」視圖,其整個操作由一系列傳送到後端或從後端接收的事件控制。最簡單的是退出按鈕:當(dāng)使用者點擊它時,會在後端觸發(fā)並偵聽退出事件,然後應(yīng)用程式關(guān)閉(onclick={() => EventsEmit("quit")})。 提示 通知使用者 Escape 鍵(快速鍵)執(zhí)行相同的操作,正如我們已經(jīng)解釋過的。

重置按鈕呼叫顯示彈出視窗的函數(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

...

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

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

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

  • 如果結(jié)果成功,請設(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

...

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

為了完成對我們應(yīng)用程式前端部分的審查,只需介紹一下「關(guān)於」組件即可。這幾乎沒有邏輯,因為它僅限於顯示有關(guān)應(yīng)用程式的信息,就像常見的 about 一樣。然而,應(yīng)該說,正如我們所看到的,該視圖顯示了指向應(yīng)用程式儲存庫的連結(jié)。顯然,在普通網(wǎng)頁中,錨標(biāo)記() 將使我們導(dǎo)航到相應(yīng)的鏈接,但在桌面應(yī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 文件。

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

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

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

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

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

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

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

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

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

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

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動的應(yīng)用程序,用於創(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.二進制體積更大:包含所有依賴導(dǎo)致文件尺寸增加,但可通過構(gòu)建標(biāo)誌或壓縮工具優(yōu)化;3.更高的可預(yù)測性與安全性:避免外部庫版本變化帶來的風(fēng)險,增強穩(wěn)定性;4.運行靈活性受限:無法熱更新共享庫,需重新編譯部署以修復(fù)依賴漏洞。這些特性使Go適用於CLI工具、微服務(wù)等場景,但在存儲受限或依賴集中管理的環(huán)境中需權(quá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函數(shù)中指定容量參數(shù)即可。緩衝通道允許發(fā)送操作在沒有接收者時暫存數(shù)據(jù),只要未超過指定容量,例如ch:=make(chanint,10)創(chuàng)建了一個可存儲最多10個整型值的緩衝通道;與無緩衝通道不同,發(fā)送數(shù)據(jù)時不會立即阻塞,而是將數(shù)據(jù)暫存於緩衝區(qū)中,直到被接收者取走;使用時需注意:1.容量設(shè)置應(yīng)合理以避免內(nèi)存浪費或頻繁阻塞;2.需防止緩衝區(qū)無限堆積數(shù)據(jù)導(dǎo)致內(nèi)存問題;3.可用chanstruct{}類型傳遞信號以節(jié)省資源;常見場景包括控制並發(fā)數(shù)量、生產(chǎ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進行系統(tǒng)編程任務(wù)? 如何使用GO進行系統(tǒng)編程任務(wù)? 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í)行外部命令、捕獲輸出、設(shè)置環(huán)境變量、重定向輸入輸出流以及控制進程生命週期,適合用於自動化工具和部署腳本;3.網(wǎng)絡(luò)與並發(fā)方面,net包支持TCP/UDP編程、DNS查詢及原始套

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

在Go語言中,調(diào)用結(jié)構(gòu)體方法需先定義結(jié)構(gòu)體和綁定接收者的方法,使用點號訪問。定義結(jié)構(gòu)體Rectangle後,可通過值接收者或指針接收者聲明方法;1.使用值接收者如func(rRectangle)Area()int,通過rect.Area()直接調(diào)用;2.若需修改結(jié)構(gòu)體,應(yīng)使用指針接收者如func(r*Rectangle)SetWidth(...),Go會自動處理指針與值的轉(zhuǎn)換;3.嵌入結(jié)構(gòu)體時,內(nèi)嵌結(jié)構(gòu)體的方法會被提升,可直接通過外層結(jié)構(gòu)體調(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關(guān)鍵字並列出方法簽名,無需顯式聲明類型實現(xiàn)了接口。常見用例包括日誌、格式化、不同數(shù)據(jù)庫或服務(wù)的抽象,以及通知系統(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