白左
千年狐狸
千年狐狸
  • UID34985
  • 注册日期2010-12-29
  • 最后登录2023-11-13
  • 发帖数2039
  • 经验655枚
  • 威望0点
  • 贡献值364点
  • 好评度69点
  • 社区居民
  • 忠实会员
阅读:1854回复:4

【已解决】(uc脚本)在右键双击事件中关闭右键菜单,菜单关闭后瞬间再次出现

楼主#
更多 发布于:2017-04-16 12:26
使用如下脚本完成“右键双击关闭当前页面”的功能

                gBrowser.mPanelContainer.addEventListener(
                        'dblclick',
                        (e)=>{
                                if(e.button == 2){
                                        e.preventDefault();
                                        e.stopPropagation();
                                        if (gBrowser.selectedTab.getAttribute("pinned") !== "true") {
                                                gBrowser.removeCurrentTab();
                                                document.getElementById("contentAreaContextMenu").hidePopup();
                                        }
                                }
                        },
                        true
                );
右键菜单右击第一次时出现,第二次时关闭,但是关闭后又立刻重新出现

图片:A (1).gif



临时解决方法为setTimeout(e=>document.getElementById("contentAreaContextMenu").hidePopup(), 50);
一般来说没问题,但浏览器比较卡的时候就会失效

为什么右键菜单会关闭后再次出现?有没有更靠谱的解决方法?
-いたんですか? -ええ、ずっと
aaaa007cn
千年狐狸
千年狐狸
  • UID23968
  • 注册日期2008-05-03
  • 最后登录2022-03-07
  • 发帖数1924
  • 经验1138枚
  • 威望1点
  • 贡献值232点
  • 好评度164点
1楼#
发布于:2017-04-17 00:31
双击在触发 dblclick 的同时也会触发两次 click 事件(还分别包括两次 mousedown 和 mouseup
但是不保证 dblclick 事件的 listener 在 click 事件的 listener 完成后才执行
类似 https://www.firefox.net.cn/read-54164 这个情况

靠谱的解决方法大概得重写显示右键菜单的代码
稍微延迟显示右键菜单
先判断这不是一个双击事件
白左
千年狐狸
千年狐狸
  • UID34985
  • 注册日期2010-12-29
  • 最后登录2023-11-13
  • 发帖数2039
  • 经验655枚
  • 威望0点
  • 贡献值364点
  • 好评度69点
  • 社区居民
  • 忠实会员
2楼#
发布于:2017-04-17 12:35
公司的电脑里还残留这远古的fx 26beta
测试了一下惊讶地发现无timeout的原始脚本可以完美运行, 也就是说, 在26beta里dblclick事件是在click之后fire的
稍微看了一下, w3c里对dblclick的描述如下(https://www.w3.org/TR/DOM-Level-3-Events/#event-type-dblclick)

This event type MUST be dispatched after the event type click if a click and double click occur simultaneously, and after the event type mouseup otherwise. As with the click event, the dblclick event should only be fired for the primary pointer button. Secondary buttons MUST NOT fire dblclick events.

w3c表示dblclick事件必须在mouseup和click之后, 与26beta的行为相符
如此说来这还是新版的bug?等回到pc前试试其他版本

不过w3c也提到dblclick只应该被左键触发, 而实际上至少从26beta起左右两键都能触发. 还好实际操作没按照标准来, 否则要实现该脚本功能的还得在走点弯路, 定义个事件什么的....
-いたんですか? -ええ、ずっと
aaaa007cn
千年狐狸
千年狐狸
  • UID23968
  • 注册日期2008-05-03
  • 最后登录2022-03-07
  • 发帖数1924
  • 经验1138枚
  • 威望1点
  • 贡献值232点
  • 好评度164点
3楼#
发布于:2017-04-17 16:21
https://www.w3.org/Bugs/Public/show_bug.cgi?id=23240
w3c 在 2013 明确禁止非主键触发 click、dblclick 事件

https://bugzilla.mozilla.org/show_bug.cgi?id=968265
没人鸟

https://bugzilla.mozilla.org/show_bug.cgi?id=1304044
直到 chrome 增加了 auxclick

dblclick 确实是在 click 之后触发的
但是 dblclick 的 listener 不一定会在 click 的 listener 执行完毕之后才执行
比如 click 的 listener 中有 callback、promise、setTimeout 等异步操作
白左
千年狐狸
千年狐狸
  • UID34985
  • 注册日期2010-12-29
  • 最后登录2023-11-13
  • 发帖数2039
  • 经验655枚
  • 威望0点
  • 贡献值364点
  • 好评度69点
  • 社区居民
  • 忠实会员
4楼#
发布于:2017-04-17 19:11
( ´・ω・`)

图片:1.png


用54a纯净配置测试了一下,确实如此,触发顺序是符合w3c的,但是右键菜单弹出却在dblclick事件触发之后
公司的26b版本却没有这个问题,可以理解为随着时间推移,右键菜单越来越臃肿,弹出的速度远远比以前慢了……起码1毫秒
新版的右键菜单包含的内容不再是单纯的文字序列,还有按钮等富元素,菜单对象变得“高级”大概是弹出速度变慢的原因之一

目前来看如果不hack的话,性价比最高的解决方案也就只有timeout了
顺便一提,微软在MSDN上给出的(通用)官方工程解决方案有两个,一个是在dblclick事件里回滚click事件的操作,消除click事件的实际效果,另一个是监听mousedown,自行判断click和dblclick
前者由于fx的情况是事件触发是click在前,事件处理click在后,显然没法在dblclick里回滚一个未来的操作……而加timeout的话,和直接timeout没什么区别,脱裤子放屁
后者要识别双击的话,牵扯到硬件参数、鼠标的系统灵敏度设置等一大票更麻烦的事情,性价比太低

不过既然右键菜单弹出比以前慢得多,几乎肯定在dblclick触发之后,那么完全可以把这个flaw当做feature:

(new RightClickTabKiller()).Init(gBrowser.mPanelContainer);

function RightClickTabKiller(){
        var self = this;
        this.isDblClicked = false;
        this.DbclickListener = e=>{
                if(e.button === 2){
                        self.isDblClicked = true;
                        // console.log(Date.now() + " dblclick: isDblClicked = true");//DEBUG
                }
        }
        this.ContextmenuListener = e=>{
                // console.log(Date.now() + " contextmenu: isDblClicked == " + self.isDblClicked);//DEBUG
                if(self.isDblClicked && e.button === 2){
                        e.preventDefault();
                        e.stopPropagation();
                        if (gBrowser.selectedTab.getAttribute("pinned") !== "true") {
                                gBrowser.removeCurrentTab();
                                document.getElementById("contentAreaContextMenu").hidePopup();
                                // console.log(Date.now() + " contextmenu: hidePopup()");//DEBUG
                        }
                }
                self.isDblClicked = false;
        }
        this.Init = contentContainer=>{
                contentContainer.addEventListener("dblclick", self.DbclickListener, true);
                contentContainer.addEventListener("contextmenu", self.ContextmenuListener, true);
        }
}


思路就是dblclick事件里不再处理任何事情,只做标记,然后在contextmenu再放具体实现
缺点是依赖于dblclick事件和contextmenu事件的先后,如果有改动肯定就废了
优点是只依赖于dblclick事件和contextmenu事件的先后,所以浏览器越卡,右键菜单弹出越慢,脚本只会更麻溜,而不会卡失效
-いたんですか? -ええ、ずっと
游客

返回顶部