🐛 修复同一 document 内重复注册的同组菜单被重复触发 - #1695
Closed
CodFrm wants to merge 1 commit into
Closed
Conversation
menuClick 收到 Popup 传来的整组菜单(`script.menus.filter(m => m.groupKey === ...)`) 后逐条 emitEventToTab。groupKey 按「name + options」生成,用意是让 mainframe 与 subframe 注册的同一个菜单在 UI 只显示一条、点击时各 frame 都执行。 但同一个 document 内重复注册同名菜单(脚本切换状态时重新 register 而没有 unregister,或每次 SPA 换页都注册一遍)也会落进同一个 groupKey,且各自持有 不同的 key。点击时这些残留 listener 会在同一个 document 里被一起触发, 开关型菜单等于连按两次,表现为点了没反应。 按 tabId + documentId(或 frameId) + groupKey 收敛,只保留最后注册的那条, 跨 document 仍分别触发,保持原本「各 frame 都执行」的语义。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checklist / 检查清单
N/A —
Code reviewed by human:尚未有人工复核。背景
PopupService.menuClick()收到 Popup 传来的整组菜单后,逐条向对应的key派发menuClick事件:Popup 点击时传的是整组:
script.menus.filter((m) => m.groupKey === menuItem.groupKey && !m.options?.inputType)(
src/pages/popup/App.tsx)。groupKey由name + options(含mIndividualKey)生成,用意写在updateMenuCommand()的注释里:mainframe 与 subframe 注册的同一个菜单在 UI 只显示一条,但点击时两边都要执行。
问题在于「同一个 document 内的重复注册」也会落进同一个
groupKey:脚本切换状态时重新GM_registerMenuCommand而没有unregisterMenuCommand,或者每次 SPA 换页都注册一遍,都会在
tabScript:<tabId>里留下多条groupKey相同、key不同、documentId相同的记录。点击时这些残留 listener 会在同一个 document 里被一起触发——开关型菜单(例如「翻译网页 / 显示原文」)
等于连按两次,用户看到的是「点了没反应」。
本次改动
menuClick()派发前按tabId + documentId(无 documentId 时退回 frameId)+ groupKey收敛,每个 key 只保留最后一条(最新注册的 listener):
跨 document / 跨 frame 的同组菜单仍然各自触发,
updateMenuCommand()注释里「subframe 和 mainframe 都会执行」的语义不变。
实现考虑
ScriptMenuItem同时带frameId与documentId,后者能区分同一 frameId 上的前后两个文档。没有
documentId的记录退回frame:<frameId>,避免把不同 frame的菜单误并成一条。
updateMenuCommand()按到达顺序 push,最后一条即最新注册的 listener;同一 document 内重复注册时,先前那条通常是脚本已经放弃的旧闭包。
individual菜单不受影响:options.mIndividualKey参与groupKey生成,显式声明不合并的菜单项本来就拿到不同的
groupKey。已知限制
两个回调都执行,改动后只会触发最新的那条。这种用法无法与「残留的旧 listener」区分;
需要各自触发时应使用
individual选项让它们拿到不同的groupKey。tabScript:<tabId>里(UI 层早就按groupKey去重显示,所以不影响观感);是否在注册侧一并清理属于另一件事,本次不扩大范围。
建议审查重点
tabId + documentId|frameId + groupKey是否恰好切在「同 document 重复注册」与「跨 frame 同名菜单」之间。
updateMenuCommand()里 REGISTER/UNREGISTER 的实际顺序语义。参考
src/app/service/service_worker/popup.ts:menuClick()/updateMenuCommand()(groupKey 生成与合并语义)src/pages/popup/App.tsx:点击时按groupKey取整组菜单验证
新增单元测试
PopupService 菜单点击分发 > 同一 document 重复注册的同组菜单只触发最新监听,跨 document 仍分别触发:三条同
groupKey记录(两条main-document、一条frame-document)→ 期望emitEventToTab只被调用 2 次,分别命中
main-2(最新)与frame-1。未做浏览器复现:改动依据是上述代码路径与单元测试,没有在真实浏览器里重放
「脚本重复注册同名菜单 → 点击无反应」的场景。若需要该级别证据请提出,我再补一份会话验证。