keydown 事件只触发一次

keydown event triggered only once

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

该脚本的目的是使 "delete conversation" 过程自动化,该过程自然包括 4 次点击,当您有数百个对话时可能会很累并且浪费时间 --- 删除将通过点击 "D"键。

我运行 Greasemonkey 的脚本。


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

  1. 监听所有 "D" 按键事件。
  2. 单击 link 打开带有 "Delete" 选项(小链轮)的模式。
  3. Clink 该模态中的 "Delete" link (它将打开第二个模态 "delete confirmation")。
  4. 单击该模式中的新 "Delete" link,以确认对话删除。

我的脚本

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() 进行迭代,我尝试使用 return dC()return false dC() 电话。所有这些都产生了相同的结果,所以我绕着圈子走,不理解(或否认)我非常想念的更深层次的逻辑错误。

正在复制

作为 Greasemonkey 脚本安装,(匹配 https:www.facebook.com/* 只是为了测试),转到对话页面并点击 "D"。

我的问题

为什么事件只被监听一次?也就是说,为什么单击 D 一次可以使脚本运行,但再单击一次则不起作用?

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

注意:我更喜欢普通的解决方案。

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

// 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 = [];
    });

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

问题出在操作 #3:

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

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

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

另一方面,每次单击设置按钮时,Facebook 都会创建一个 新的“.uiContextualLayer”(定位菜单链轮 link 并展开您的开发工具window注意添加的新元素)。

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

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);
};