Wails提供了丰富的功能,使开发者能够构建功能强大的桌面应用。本节将详细介绍Wails的核心功能及其使用方法。
原生UI元素
Wails提供了对原生UI元素的支持,使应用能够与操作系统无缝集成。
菜单
Wails允许创建原生菜单,包括应用菜单、上下文菜单和托盘菜单。
go
package main
import (
"context"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/menu"
"github.com/wailsapp/wails/v2/pkg/options"
)
// App 结构体
type App struct {
ctx context.Context
}
// 创建应用菜单
func (a *App) createApplicationMenu() *menu.Menu {
appMenu := menu.NewMenu()
// 文件菜单
fileMenu := appMenu.AddSubmenu("File")
fileMenu.AddText("&New", nil, a.onNew)
fileMenu.AddText("&Open", nil, a.onOpen)
fileMenu.AddSeparator()
fileMenu.AddText("&Save", nil, a.onSave)
fileMenu.AddText("Save &As", nil, a.onSaveAs)
fileMenu.AddSeparator()
fileMenu.AddText("&Quit", keys.CmdOrCtrl("q"), a.onQuit)
// 编辑菜单
editMenu := appMenu.AddSubmenu("Edit")
editMenu.AddText("&Undo", keys.CmdOrCtrl("z"), a.onUndo)
editMenu.AddText("&Redo", keys.CmdOrCtrl("shift+z"), a.onRedo)
editMenu.AddSeparator()
editMenu.AddText("Cu&t", keys.CmdOrCtrl("x"), a.onCut)
editMenu.AddText("&Copy", keys.CmdOrCtrl("c"), a.onCopy)
editMenu.AddText("&Paste", keys.CmdOrCtrl("v"), a.onPaste)
return appMenu
}
// 菜单回调函数
func (a *App) onNew(_ context.Context) {
// 处理新建操作
}
func (a *App) onOpen(_ context.Context) {
// 处理打开操作
}
// ... 其他回调函数
func main() {
app := NewApp()
err := wails.Run(&options.App{
Title: "Menu Demo",
Width: 800,
Height: 600,
Menu: app.createApplicationMenu(),
OnStartup: app.OnStartup,
OnDomReady: app.OnDomReady,
OnShutdown: app.OnShutdown,
})
if err != nil {
println("Error:", err.Error())
}
}
前后端通信
Wails提供了强大的前后端通信机制,使前端JavaScript能够轻松调用后端Go方法,并支持双向事件通信。
方法调用
Wails自动将导出的Go方法暴露给前端JavaScript,使得前端可以直接调用这些方法:
go
// Go后端代码
package main
import (
"context"
"fmt"
"time"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/options"
)
// User 结构体
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
IsActive bool `json:"isActive"`
}
// App 结构体
type App struct {
ctx context.Context
}
// 获取用户信息
func (a *App) GetUser(id int) (*User, error) {
// 模拟从数据库获取用户
if id == 1 {
return &User{
ID: 1,
Name: "John Doe",
Email: "john@example.com",
IsActive: true,
}, nil
}
return nil, fmt.Errorf("User not found")
}
// 获取用户列表
func (a *App) GetUserList() ([]User, error) {
// 模拟从数据库获取用户列表
users := []User{
{ID: 1, Name: "John Doe", Email: "john@example.com", IsActive: true},
{ID: 2, Name: "Jane Smith", Email: "jane@example.com", IsActive: true},
{ID: 3, Name: "Bob Johnson", Email: "bob@example.com", IsActive: false},
}
return users, nil
}
// 执行耗时操作
func (a *App) LongRunningOperation(seconds int) (string, error) {
// 模拟耗时操作
time.Sleep(time.Duration(seconds) * time.Second)
return fmt.Sprintf("Operation completed after %d seconds", seconds), nil
}
javascript
// 前端JavaScript代码
// 获取单个用户
async function getUser() {
try {
const user = await window.backend.App.GetUser(1);
console.log("User:", user);
return user;
} catch (error) {
console.error("Error getting user:", error);
return null;
}
}
// 获取用户列表
async function getUserList() {
try {
const users = await window.backend.App.GetUserList();
console.log("Users:", users);
return users;
} catch (error) {
console.error("Error getting user list:", error);
return [];
}
}
// 执行耗时操作
async function performLongOperation() {
try {
const result = await window.backend.App.LongRunningOperation(3);
console.log("Result:", result);
return result;
} catch (error) {
console.error("Error performing long operation:", error);
return null;
}
}
事件系统
Wails提供了统一的事件系统,支持Go和JavaScript之间的双向事件通信:
go
// Go后端发送事件
func (a *App) SendNotification() {
a.runtime.Events.Emit("notification", "New message received")
}
javascript
// 前端JavaScript监听事件
window.runtime.EventsOn("notification", (message) => {
console.log("Notification:", message);
// 显示通知
});
文件系统操作
Wails提供了丰富的文件系统操作功能,使应用能够读写文件、目录等。
go
package main
import (
"context"
"os"
"path/filepath"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/options"
)
// App 结构体
type App struct {
ctx context.Context
}
// 读取文件内容
func (a *App) ReadFile(path string) (string, error) {
content, err := os.ReadFile(path)
if err != nil {
return "", err
}
return string(content), nil
}
// 写入文件内容
func (a *App) WriteFile(path, content string) error {
return os.WriteFile(path, []byte(content), 0644)
}
// 检查文件是否存在
func (a *App) FileExists(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
// 创建目录
func (a *App) CreateDirectory(path string) error {
return os.MkdirAll(path, 0755)
}
// 删除文件
func (a *App) DeleteFile(path string) error {
return os.Remove(path)
}
// 删除目录
func (a *App) DeleteDirectory(path string) error {
return os.RemoveAll(path)
}
// 列出目录内容
func (a *App) ListDirectory(path string) ([]string, error) {
entries, err := os.ReadDir(path)
if err != nil {
return nil, err
}
var files []string
for _, entry := range entries {
files = append(files, entry.Name())
}
return files, nil
}
// 获取文件信息
func (a *App) GetFileInfo(path string) (map[string]interface{}, error) {
info, err := os.Stat(path)
if err != nil {
return nil, err
}
fileInfo := map[string]interface{}{
"name": info.Name(),
"size": info.Size(),
"mode": info.Mode(),
"modTime": info.ModTime(),
"isDir": info.IsDir(),
}
return fileInfo, nil
}
// 获取应用数据目录
func (a *App) GetAppDataDir() (string, error) {
// 获取用户数据目录
userDataDir, err := os.UserConfigDir()
if err != nil {
return "", err
}
// 创建应用特定的数据目录
appDataDir := filepath.Join(userDataDir, "myapp")
err = os.MkdirAll(appDataDir, 0755)
if err != nil {
return "", err
}
return appDataDir, nil
}
系统集成
Wails提供了与操作系统深度集成的功能,使应用能够访问系统级功能。
系统托盘
go
package main
import (
"context"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/menu"
"github.com/wailsapp/wails/v2/pkg/options"
"github.com/wailsapp/wails/v2/pkg/options/mac"
"github.com/wailsapp/wails/v2/pkg/options/windows"
)
// App 结构体
type App struct {
ctx context.Context
}
// 创建托盘菜单
func (a *App) createTrayMenu() *menu.Menu {
trayMenu := menu.NewMenu()
// 显示/隐藏窗口
if a.runtime.Window.IsVisible() {
trayMenu.AddText("Hide", nil, func(_ context.Context) {
a.runtime.Window.Hide()
})
} else {
trayMenu.AddText("Show", nil, func(_ context.Context) {
a.runtime.Window.Show()
})
}
trayMenu.AddSeparator()
// 退出应用
trayMenu.AddText("Quit", nil, func(_ context.Context) {
a.runtime.Quit()
})
return trayMenu
}
func main() {
app := NewApp()
err := wails.Run(&options.App{
Title: "Tray Demo",
Width: 800,
Height: 600,
Tray: &options.Tray{
Icon: "build/appicon.png",
Menu: app.createTrayMenu(),
Tooltip: "Tray Demo App",
},
OnStartup: app.OnStartup,
OnDomReady: app.OnDomReady,
OnShutdown: app.OnShutdown,
})
if err != nil {
println("Error:", err.Error())
}
}
系统通知
go
package main
import (
"context"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/options"
)
// App 结构体
type App struct {
ctx context.Context
}
// 显示系统通知
func (a *App) ShowNotification(title, message string) {
a.runtime.Notification.Notify(title, message)
}
// 显示带图标的系统通知
func (a *App) ShowNotificationWithIcon(title, message, iconPath string) {
a.runtime.Notification.Notify(title, message)
// 注意:图标支持可能因平台而异
}