视图
组件在挂载时构建界面。当子节点需要随状态出现、消失或重新排序时,使用 ui.Show 和 ui.For。
#视图如何工作
每个组件都返回 *ui.Element。用 .Child(...) 或 .Children(...) 传入子节点。多个兄弟节点可以返回 ui.Fragment(...),无需额外包裹。
func ViewExample() *ui.Element {
return ui.View().Padding(20).Gap(12).Children(
ui.Text("Hello from Go"),
ui.Button().Child("Continue").OnClick(func() {}),
)
}普通的 Go if 或 for 只在构建组件时运行,之后不会再更新。
#条件内容
用 ui.Show 根据状态挂载或移除子节点。
func DisclosureExample() *ui.Element {
open, setOpen := ui.CreateSignal(false)
return ui.View().Children(
ui.Button().Child("Toggle details").OnClick(func() { setOpen(!open()) }),
ui.Show(
open,
func() *ui.Element { return ui.Text("Details") },
),
)
}#列表
用 ui.For 渲染会变化的列表。给每一行稳定且唯一的 key——用数据库 ID,不要用下标。ui.KeyedFor 还会给行一个访问当前项的 accessor。
type ListPerson struct {
ID int
Name string
}
func KeyedListExample() *ui.Element {
people, setPeople := ui.CreateSignal([]ListPerson{{1, "Ada"}, {2, "Grace"}})
return ui.View().Children(
ui.Button().Child("Reorder and rename").OnClick(func() {
setPeople([]ListPerson{{2, "Grace"}, {1, "Ada Lovelace"}})
}),
ui.KeyedFor(
people,
func(person ListPerson) any { return person.ID },
func(person func() ListPerson, index func() int) *ui.Element {
return ui.Text(
index(),
": ",
person().Name,
)
},
func() *ui.Element { return ui.Text("No people") },
),
)
}编辑数据时传入新的切片。原地修改已存储的切片不会通知订阅者。长列表请使用 VirtualList 或 Table。
#窗口生命周期
每个窗口有自己的组件根。关闭窗口会释放它的界面和 effect。用 ui.OnCleanup 注册清理。ui.Async 在 UI goroutine 之外运行工作,把结果送回,并在组件消失时取消。
func LoadingPanel(load func(context.Context) (string, error)) *ui.Element {
result, setResult := ui.CreateSignal("Loading…")
ui.Async(
load,
func(value string, err error) {
if err != nil {
setResult(err.Error())
return
}
setResult(value)
},
)
return ui.Text(result())
}#当前窗口
在组件挂载时捕获 native.CurrentWindow(),然后在回调里使用这个句柄。
func CloseButton() *ui.Element {
window := native.CurrentWindow()
return ui.Button().Child("Close window").OnClick(func() { window.Close() })
}#测试
在应用模块中运行 quickgui test。quickgui fmt --check 检查格式。应用是 Go 可执行文件,因此常用的 Go 调试器和堆栈会指向你的源文件。
