【问题标题】:keydown event triggered only oncekeydown 事件仅触发一次
【发布时间】:2017-09-04 02:47:53
【问题描述】:

以下脚本旨在在 facebook.com 的对话页面(用户可以查看其所有对话的页面)上运行。

该脚本的目的是自动化“删除对话”过程,该过程自然包括 4 次点击,当您有数百个对话时可能会很烦人且浪费时间 --- 删除将通过按“D”键从键盘完成。

我用 Greasemonkey 运行脚本。


脚本由 4 个主要部分组成:

  1. 收听所有“D”键击事件。
  2. 点击打开带有“删除”选项的模态的链接(小链轮)。
  3. 单击该模式中的“删除”链接(它将打开第二个模式“删除确认”)。
  4. 点击该模式中新的“删除”链接,以确认对话删除。

我的脚本

document.addEventListener('keydown', (k)=>{
    if ( k.keyCode === 68 ) {
        console.log('keydown: D');
        return dC();
    }
});

let dC = ()=>{
    document.querySelector('._5blh._4-0h').click();
    document.querySelector('.uiContextualLayer > [id^="js"] > div > ul > li:nth-child(4)').click();
    setTimeout(()=>{ document.querySelector('._3quh._30yy._2t_._3ay_._5ixy').click(); }, 500);
};

作为一个初学者,我尝试将部分代码放入函数中,我尝试使用for 而不是forEach() 进行迭代,我尝试在dC() 调用下使用return dC()return false。所有这些都产生了相同的结果,所以我绕着圈子不理解(或否认)我非常想念的更深层次的逻辑错误。

复制

安装为 Greasemonkey 脚本,(匹配为 https:www.facebook.com/* 仅用于测试),进入对话页面并点击“D”。

我的问题

为什么事件只被监听一次?也就是说,为什么单击 D 一次会使脚本工作,但任何进一步的单击都无济于事?

我必须刷新页面才能重用脚本,这不是预期的行为。

注意:我更喜欢原版解决方案。

【问题讨论】:

  • 如果document.querySelector(' ._5blh._4-0h ') 没有找到任何东西,那么脚本的其余部分将不会运行,因为document.querySelector(' ._5blh._4-0h ').click(); 抛出的错误
  • 我发誓它会为我找到并打开模态...
  • 哦,我不是说这是你的问题,我是说如果失败了,那么下面的代码甚至不会运行 - 你检查过 developer 工具了吗控制台是否有任何错误?
  • 是的,好几次。那里没有错误 - 事实上,如果我单击“D”并移动直到卡在第 2 段,但在控制台中运行第 3 段 --- 它可以工作(对话被删除)......但我仍然可以'点击“D”时重用脚本。
  • 你肯定在这段代码或其他地方有一个错误......或者点击正在触发,但也许对话并没有真正删除(即删除)而是隐藏在 DOM 中,所以之后第一个 keydown 看起来什么都没有发生,但事件仍在隐藏元素上触发。请参阅:jsfiddle.net/wmvLv7jL 您可以按住 D 键或多次按下它 - 它显然有效。

标签: javascript loops events keyboard-shortcuts


【解决方案1】:

正如所写,函数 dC(),它执行 4 个操作:

问题出在操作 #3

看起来,每次点击 'settings' 菜单(action #2),都会创建一个新的 'settings-menu' 实例(新对象添加到 DOM),因此这一行不会工作:

document.querySelector('.uiContextualLayer > [id^="js"] > div > ul > li:nth-child(4)').click ();

一方面,querySelector 返回回答给定模式的 first 元素。

另一方面,Facebook 会在每次单击设置按钮时创建一个新的 '.uiContextualLayer'(定位菜单链轮链接并展开您的开发工具窗口以记录添加的新元素)。

因此,我们要做的是检查所有链轮元素之后,然后每次都使用最新(最后一个)元素:

let menu = document.querySelectorAll('.uiContextualLayer._5v-0._53il');
menu = menu[menu.length-1];


这是最终代码
(我添加了几个超时以确保完成 UI 绘制)

let dC = ()=>
{
  // clicking the 'settings'
  document.querySelector('._5blh._4-0h').click();
  setTimeout(() => {
    // taking the last instance of 'menu popup':
    let menu = document.querySelectorAll('.uiContextualLayer._5v-0._53il');
    menu = menu[menu.length-1];

    // finding 'delete' button inside the menu popup
    let lis = menu.querySelectorAll('ul > li');
    let target = null;
    for (let i=0;!target && i<lis.length;++i)
    {
        let span = lis[i].querySelector('a span span');
        if (!span) continue;
        if (span.innerHTML.contains('Delete'))
            target = lis[i];
    }
    if (!target) {console.log('cannot find delete btn'); return;}


    // clicking 'delete' button in menu
    setTimeout(() => {
        target.click();

        setTimeout(()=>{ 
            // clicking delete in modal
            document.querySelector('._3quh._30yy._2t_._3ay_._5ixy').click(); 
        }, 500);

    }, 10);
  },10);
};

【讨论】:

    【解决方案2】:

    将键值推入数组并在事件结束后取消设置这些数组。

    // Create two empty arrays
        var map = [];
        var down = [];
    
        $(document).on('keydown', 'body', function(e) {
    // Check whether the map having any key values
          if (!map[e.which]) {
    // Set the keydown value to down array
            down.push(e.which);
    
            if (down[0] === 68) {
              // Events to be done
            }
          }
    
        map[e.which] = true;
    // Once the key-down pressed and event done ,the keyup unset the array while key up 
        }).keyup(function(e) {
          map[e.which] = false;
    
          // unset(down,e.which);  
          down = [];
          e.which = [];
        });
    

    【讨论】:

    • @user8551674 我会尝试它是否有用,并使其被接受,这样它也将帮助其他人
    • 当然没问题。我会自己编辑,但我更愿意让您有幸将其制作为香草,我的编辑因偏离 OP 的意图而被拒绝...
    • Harish,能否请您添加有关正在做什么的 cmets?对我个人来说,这不是很清楚,对我来说学习很重要。另外,我相信这可以确保获得更多好评。
    • @user8551674 我用 cmets 更新了代码,我只是将按键值设置为数组并销毁 keyup 上的事件。目的是避免在单独按下时发生事件,例如:shift+g- > 某些事件:该事件仅在我同时按下两者时才会发生,否则它不会发生
    • @user8551674 这就是 $(document).on('keydown', 'body', function(e) {...} "当文档被点击时的确切含义,如果它与正文然后触发此代码“”要了解更多详细信息,请点击链接:“stackoverflow.com/questions/14879168/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 2020-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多