应用开发
使用 Wails 开发应用程序没有硬性规定,但有一些基本准则。
应用程序设置
默认模板使用 main.go 配置和运行应用程序, 同时app.go 用于定义应用程序逻辑.
app.go文件将定义一个结构体,该结构体有 2 个方法作为主应用程序的回调:
type App struct {
ctx context.Context
}
func NewApp() *App {
return &App{}
}
func (a *App) startup(ctx context.Context) {
a.ctx = ctx
}
func (a *App) shutdown(ctx context.Context) {
}
-
一旦 Wails 分配了它需要的资源,就会调用 startup 方法,它是创建资源、设置事件侦听器以及应用程序在启动时需要的任何其他东西的好地方。 它提供了一个
context.Context, 通常保存在一个结构体字段中。 调用 运行时 需要此context.Context。 如果此方法返回错误,则应用程序将终止。 在开发模式下,错误会输出到控制台。 -
Shutdown 方法将在关闭过程结束时由 Wails 调用。 这是释放内存和执行关闭任务的好地方。
main.go 文件通常由对wails.Run()的单个调用组成,它接受应用程序配置。 模板使用的模式是,在调用 wails.Run() 之前, 我们创建并保存一个在 app.go 中定义的结构体的实例在名为 app 的变量中。 这个配置是我们添加回调的地方:
func main() {
app := NewApp()
err := wails.Run(&options.App{
Title: "My App",
Width: 800,
Height: 600,
OnStartup: app.startup,
OnShutdown: app.shutdown,
})
if err != nil {
log.Fatal(err)
}
}
可以在 此处 找到有关应用程序生命周期回调的更多信息。
绑定方法
您可能希望从前端调用 Go 方法。 这通常是通过向 app.go 中已经定义的结构体中添加公共方法来实现的:
type App struct {
ctx context.Context
}
func NewApp() *App {
return &App{}
}
func (a *App) startup(ctx context.Context) {
a.ctx = ctx
}
func (a *App) shutdown(ctx context.Context) {
}
func (a *App) Greet(name string) string {
return fmt.Sprintf("Hello %s!", name)
}
在主应用程序中,Bind 字段是我们告诉 Wails 想要绑定什么:
func main() {
app := NewApp()
err := wails.Run(&options.App{
Title: "My App",
Width: 800,
Height: 600,
OnStartup: app.startup,
OnShutdown: app.shutdown,
Bind: []interface{}{
app,
},
})
if err != nil {
log.Fatal(err)
}
}
这将绑定 App 结构中的所有公共方法(它永远不会绑定 startup 和 shutdown 方法)。
绑定多个结构体时处理 context
如果您想为多个结构绑定方法,但希望每个结构都保留对 context 的引用,以便您可以使用运行时函数,一个好的方式是将上下文从 OnStartup 方法传递给您的结构实例:
func main() {
app := NewApp()
otherStruct := NewOtherStruct()
err := wails.Run(&options.App{
Title: "My App",
Width: 800,
Height: 600,
OnStartup: func(ctx context.Context){
app.SetContext(ctx)
otherStruct.SetContext(ctx)
},
OnShutdown: app.shutdown,
Bind: []interface{}{
app,
otherStruct
},
})
if err != nil {
log.Fatal(err)
}
}
Also you might want to use Enums in your structs and have models for them on frontend. In that case you should create array that will contain all possible enum values, instrument enum type and bind it to the app:
type Weekday string
const (
Sunday Weekday = "Sunday"
Monday Weekday = "Monday"
Tuesday Weekday = "Tuesday"
Wednesday Weekday = "Wednesday"
Thursday Weekday = "Thursday"
Friday Weekday = "Friday"
Saturday Weekday = "Saturday"
)
var AllWeekdays = []struct {
Value Weekday
TSName string
}{
{Sunday, "SUNDAY"},
{Monday, "MONDAY"},
{Tuesday, "TUESDAY"},
{Wednesday, "WEDNESDAY"},
{Thursday, "THURSDAY"},
{Friday, "FRIDAY"},
{Saturday, "SATURDAY"},
}
In the main application configuration, the EnumBind key is where we can tell Wails what we want to bind enums as well:
func main() {
app := NewApp()
err := wails.Run(&options.App{
Title: "My App",
Width: 800,
Height: 600,
OnStartup: app.startup,
OnShutdown: app.shutdown,
Bind: []interface{}{
app,
},
EnumBind: []interface{}{
AllWeekdays,
},
})
if err != nil {
log.Fatal(err)
}
}
This will add missing enums to your model.ts file.
可以在 此处 找到有关绑定的更多信息。
应用程序菜单
Wails 支持向您的应用程序添加菜单。 这是通过将 菜单结构体 传递给应用程序配置来完成的。 常见做法是使用一个返回菜单的方法,更常见的是用作生命周期回调的 App 结构体上的方法。
func main() {
app := NewApp()
err := wails.Run(&options.App{
Title: "My App",
Width: 800,
Height: 600,
OnStartup: app.startup,
OnShutdown: app.shutdown,
Menu: app.menu(),
Bind: []interface{}{
app,
},
})
if err != nil {
log.Fatal(err)
}
}
资产
Wails v2 处理资源的方式的伟大之处在于它不需要处理! 您唯一需要给 Wails 的是一个 embed.FS。 你如何做到这一点完全取决于你。 您可以像 vanilla 模板一样使用 vanilla html/css/js 文件。 您可能有一些复杂的构建系统,但这并不影响。
运行 wails build 时,它会检查项目根目录的 wails.json 文件。 文件中有 2 个字段会被读取:
- "frontend:install"
- "frontend:build"
第一个,如果有给定,将在 frontend 目录中执行以安装 node 模块。 第二个,如果有给定,将在 frontend 目录中执行以构建前端项目。
如果没有给出这两个字段,那么 Wails 不会对前端做任何操作。 它仅仅被用作 embed.FS。