十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Wails v3 右键上下文菜单(Context Menu)实战:窗口级、全局菜单与前端 CSS 样式驱动

Wails v3 右键上下文菜单(Context Menu)实战:窗口级、全局菜单与前端 CSS 样式驱动 Wails v3 右键上下文菜单Context Menu实战窗口级、全局菜单与前端 CSS 样式驱动【免费下载链接】wailsCreate beautiful applications using Go项目地址: https://gitcode.com/gh_mirrors/wa/wails导读本篇文章以 Wails v3 官方示例 v3/examples/contextmenus 为骨架系统讲解如何在 Wails v3 应用中创建窗口级右键上下文菜单Context Menu并通过前端 CSS 自定义属性--custom-contextmenu、--custom-contextmenu-data、--default-contextmenu把菜单精准挂载到任意 DOM 元素、向 Go 回调传递上下文数据、以及控制浏览器默认右键菜单的显隐。读完本文你将掌握从 Go 侧注册菜单、到前端元素绑定、再到回调中读取上下文数据的完整闭环并理解 macOS 私有 API 构建标签private_mac_apis在透明背景场景下的作用与限制。一、示例概览contextmenus 演示了什么v3/examples/contextmenus示例的核心目标非常聚焦演示窗口级window level与全局global上下文菜单的创建方式以一个 id 为test的简单菜单为例将其注册到应用application从而对任意窗口生效在前端 HTML 中通过--custom-contextmenu样式把该菜单附加到指定元素通过--custom-contextmenu-data样式把自定义数据传给菜单回调并在 Go 侧读取——这在用组件区分不同元素例如列表中的不同条目时非常有用。示例的目录结构极简全部代码仅三个文件v3/examples/contextmenus/ ├── README.md # 示例说明 ├── main.go # Go 侧创建应用、定义并注册上下文菜单 └── assets/ └── index.html # 前端通过 CSS 属性绑定菜单与默认菜单控制二、Go 侧实现创建并注册上下文菜单先看 main.go 的完整实现它是整个示例的入口package main import ( embed log github.com/wailsapp/wails/v3/pkg/application ) //go:embed assets var assets embed.FS func main() { app : application.New(application.Options{ Name: Context Menu Demo, Description: A demo of the Context Menu API, Assets: application.AssetOptions{ Handler: application.BundledAssetFileServer(assets), }, Mac: application.MacOptions{ ApplicationShouldTerminateAfterLastWindowClosed: true, }, }) app.Window.NewWithOptions(application.WebviewWindowOptions{ Title: Context Menu Demo, Width: 1024, Height: 1024, Mac: application.MacWindow{ Backdrop: application.MacBackdropTranslucent, TitleBar: application.MacTitleBarHiddenInsetUnified, InvisibleTitleBarHeight: 50, }, }) contextMenu : app.ContextMenu.New() clickMe : contextMenu.Add(Click to set Menuitem label to Context Data) contextDataMenuItem : contextMenu.Add(Current context data: No Context Data) clickMe.OnClick(func(data *application.Context) { app.Logger.Info(Context menu, context data, data.ContextMenuData()) contextDataMenuItem.SetLabel(Current context data: data.ContextMenuData()) contextMenu.Update() }) // Register the context menu app.ContextMenu.Add(test, contextMenu) err : app.Run() if err ! nil { log.Fatal(err.Error()) } }2.1 关键步骤拆解创建应用与窗口通过application.New(...)初始化应用BundledAssetFileServer把assets目录以//go:embed方式嵌入并提供给 webview窗口宽高均为 1024并配置了 macOS 的半透明背景MacBackdropTranslucent与隐藏式统一样式标题栏MacTitleBarHiddenInsetUnified。创建菜单app.ContextMenu.New()返回一个全新的*ContextMenu对象。添加菜单项contextMenu.Add(label)追加菜单项并返回*MenuItem随后即可对菜单项绑定点击回调。绑定回调clickMe.OnClick(func(data *application.Context){ ... })——回调收到的*application.Context携带本次右键触发时的上下文信息。注册菜单app.ContextMenu.Add(test, contextMenu)把该菜单以字符串 idtest注册到应用级因此它可以被任意窗口中的任意元素通过 id 引用。启动app.Run()进入事件循环。2.2 回调中的上下文数据点击菜单项时回调参数data *application.Context提供了三个实用方法见 v3/pkg/application/context.go方法返回类型说明ClickedMenuItem()*MenuItem被点击的菜单项对象IsChecked()bool该项是否为选中勾选/单选状态ContextMenuData()string前端通过--custom-contextmenu-data传入的字符串数据示例中点击菜单项后会做三件事打印上下文数据到日志、动态修改另一个菜单项的标签SetLabel、并调用contextMenu.Update()将菜单变更同步到各平台的原生实现。从源码看Context.Update()在注册后会把菜单按名称重新Add回应用v3/pkg/application/menu.go#L21-L26从而保证动态修改对平台菜单生效。2.3 底层流转前端事件如何到达 Go 回调前端右键事件到 Go 回调的完整链路可以从以下源码中印证前端运行时在DOMContentLoaded时注册全局contextmenu事件监听v3/internal/runtime/desktop/wailsio/runtime/src/contextmenu.ts命中自定义菜单后运行时调用openContextMenu(id, x, y, data)把菜单 id、鼠标坐标与附加数据发给 Go 侧Go 侧 messageprocessor_contextmenu.go 把请求参数解析为ContextMenuData字段含Id、X、Y、Data即菜单 id、触发坐标与自定义数据再调用window.OpenContextMenu(...)展示原生菜单并派发点击事件最终回调收到的Context中ContextMenuData()正是解析后的Data字段v3/pkg/application/context.go#L56-L62。这解释了为什么示例能“用组件区分不同元素”前端每个元素可以携带不同的--custom-contextmenu-dataGo 回调据此判断用户右键的是哪一个。三、前端绑定CSS 自定义属性驱动菜单示例前端 assets/index.html 使用自定义 CSS 属性把菜单挂到元素上同时演示了默认上下文菜单的精细控制。核心代码div classregion id123abc style--custom-contextmenu: test; --custom-contextmenu-data: 1 h11/h1 /div div classregion id234abc style--custom-contextmenu: test; --custom-contextmenu-data: 2 h12/h1 /div两个div都引用了 id 为test的菜单与 Go 侧app.ContextMenu.Add(test, contextMenu)一一对应但分别携带数据1与2。右键时运行时读取getComputedStyle(target).getPropertyValue(--custom-contextmenu)得到菜单 id再读取--custom-contextmenu-data作为数据随事件发送contextmenu.ts#L30-L43。3.1 三个 CSS 属性的语义CSS 属性取值作用--custom-contextmenu已注册的菜单 id用自定义菜单替换该元素上的默认右键菜单--custom-contextmenu-data任意字符串附加数据随右键事件传给 Go 回调--default-contextmenuauto/show/hide控制**默认系统/浏览器**右键菜单在该元素上的行为3.2 默认菜单的智能控制auto/show/hide默认菜单的处理逻辑在 contextmenu.ts#L46-L98 中实现三种取值的行为如下auto默认值智能模式——当目标元素contenteditable为 true、或已有选中文本且选区矩形命中目标元素、或是input/textarea且有选区或非只读、非禁用时显示默认菜单否则隐藏。show始终显示默认菜单。hide始终隐藏默认菜单。该规则像普通 CSS 一样被继承因此嵌套元素会自然沿用父级设置形成局部覆盖、逐层恢复的效果。示例页面中第二、三、四个区域分别演示了这三种组合值得对照阅读assets/index.html#L40-L80!-- 区域三默认显示但输入框内隐藏 -- div classregion id123abcg style--default-contextmenu: show h1Default Context Menu shown here/h1 label input typetext placeholdercontext menu hidden here style--default-contextmenu: hide/ /label /div!-- 区域四智能模式含 contenteditable、选中文本、禁用/只读输入框等边界情况 -- div classregion id123abcgr h1Default auto (smart) Context Menu here/h1 ... div styleuser-select: text pContext menu shown here only if you select text/p ... /div div input typetext valueinput input typetext valuedisabled disabled input typetext valuereadonly readonly textarea placeholdercontext menu shown here/textarea p contenteditabletruecontent editable/p /div /div!-- 区域五默认隐藏但输入框内恢复、嵌套区回退到智能模式 -- div classregion id234abcs style--default-contextmenu: hide ... div style--default-contextmenu: auto div styleborder: solid 2px white; margin: 10px h2Nested section reverted to auto (smart) default Context Menu/h2 ... /div /div /div这些用例覆盖了真实应用中常见的边界场景普通文本区、可选文本、文本框正常/禁用/只读、文本域、可编辑元素以及嵌套恢复。从源码可以确认开发debug构建默认总是显示菜单if (IsDebug()) { return; }见 contextmenu.ts#L54-L57因此上述智能隐藏行为需要以生产模式运行才能完整体验示例页面顶部的提示命令即为go run -tags production .。四、平台支持状态原文档给出的平台状态表如下它基于当前仓库的实际情况PlatformStatusMacWorkingWindowsWorkingLinux未标注从源码结构看Linux 的菜单实现如 linux_cgo.go 与 linux_cgo_gtk3.go 中的contextMenuShow同样存在因此该表格应理解为当前示例在 Linux 上尚未标注验证状态而非能力缺失。需要强调的是示例中的半透明 macOS 背景、隐藏式标题栏等窗口外观在非 macOS 平台不生效但上下文菜单 API 本身与前端绑定方式在各平台保持一致。五、macOS 私有 API 与private_mac_apis构建标签示例页面使用半透明 macOS 背景MacBackdropTranslucent而要让 webview 真正透明、露出背后的原生背景需要启用private macOS APIs构建标签否则示例会在原生背景之上显示一个不透明的 webview。在示例目录下使用私有 API 运行go run -tags private_mac_apis .省略-tags private_mac_apis则仅使用公开 macOS API。private_mac_apis标签对 Windows、Linux、iOS、Android 均无影响。5.1 标签的选择逻辑与生产构建从构建约束源码可以印证标签的分流机制mac_private_api_darwin.go的构建约束为darwin !ios !server private_mac_apisv3/pkg/application/mac_private_api_darwin.go#L1而mac_public_api_darwin.go的约束为不带该标签v3/pkg/application/mac_public_api_darwin.go#L1二者互斥选择。启用标签后macOS 会编译私有 API 实现不启用时相关私有操作退化为 no-op同时保留公开 API 的替代方案。生成生产二进制时把标签合并传入即可go build -tags production,private_mac_apis .其中production标签会关闭调试相关能力如默认禁用 inspector如需在产物中保留检查器快捷键可追加devtoolsgo build -tags production,devtools,private_mac_apis .共享私有 API 指南含生产构建与回退细节位于 v3/examples/README.md#private-macos-apis。从该指南可知透明 webview 覆盖半透明原生背景这一需求正是 badge、dock、notifications、spotlight 等多个示例共同依赖该标签的原因不带标签时这些示例的 webview 保持不透明。六、运行与编译示例本示例直接使用 Go 工具链运行即可v3/examples/README.md#L6-L17cd v3/examples/contextmenus go mod tidy go run .编译为独立二进制cd v3/examples/contextmenus go mod tidy go build ./contextmenus注意事项若使用基于任务Taskfile的示例请使用wails3 build/wails3 dev等构建管线并以EXTRA_TAGSprivate_mac_apis传入标签本示例不涉及。示例目录属于 Wails v3 主模块v3/go.mod运行时需保证在仓库内拥有可用的 Go 模块环境。完整体验默认菜单的智能隐藏行为请以生产模式运行如go run -tags production .。七、小结与延伸阅读通过contextmenus示例我们完整走通了 Wails v3 上下文菜单的四个层次Go 侧定义app.ContextMenu.New()Add(label)OnClick(...)全局注册app.ContextMenu.Add(test, contextMenu)使菜单对所有窗口、所有元素可见前端绑定--custom-contextmenu指定菜单 id、--custom-contextmenu-data传数据、--default-contextmenu控制默认菜单的显示策略回调消费data.ContextMenuData()读取前端数据SetLabelUpdate()实现菜单动态更新。相关源码与文档位置便于继续深入示例主程序v3/examples/contextmenus/main.go示例前端v3/examples/contextmenus/assets/index.html前端运行时菜单处理逻辑v3/internal/runtime/desktop/wailsio/runtime/src/contextmenu.ts菜单与 ContextMenu 实现v3/pkg/application/menu.go回调上下文对象v3/pkg/application/context.go前端消息处理与数据结构v3/pkg/application/messageprocessor_contextmenu.gomacOS 私有 API 标签说明v3/examples/README.md#private-macos-apis【免费下载链接】wailsCreate beautiful applications using Go项目地址: https://gitcode.com/gh_mirrors/wa/wails创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表