2

(编辑了一些拼写错误)

所以这里有一段代码在用户对 MPC 问题的每个回答中重复出现:

  • 它触发问题,生成 4 个答案,将“单击”和“鼠标悬停”绑定到答案,并等待用户实际单击其中一个。
  • 当他这样做时,它会检查它是对还是错,将其显示给用户,然后在继续并重复之前等待另一个输入(这次是文档中的任何地方)。

现在,这个想法是用户可以用光标单击,或者使用 QWER 来回答。由于我对操纵事件及其数据还很陌生,所以我找到了一种(显然是有缺陷的)将两者分开的方法,如下所示。

但是,当用户通过单击“回答”并通过 QWER “继续”时,它会过快地完成整个事情,实际上按预期触发问题,然后立即回答并再次触发另一个问题。(并且在将其花费的时间提取到一个数组中之后,我发现它有时会连续执行 3-6 次,而根本没有明显的理由说明这样做了多少次......)

现在,如前所述,我在事件方面是新手,因此(e)可能存在冗余和/或错误用法,但请耐心等待。当然,我希望这个错误与此有关。此外,有些函数在这里是无关紧要的,因为它们会返回到它们调用所在的任何函数(right();例如,它本身不会触发任何东西)。

这里的重点是循环。

提前致谢!

这是代码:

function keyAns() {
    answered="no";
    draw(0);
}

function keyNotAns (A) {
    B = $(A).children('.answer');
    if ($(B).hasClass('right')) {
        // do something
    }
    else if ($(B).hasClass('wrong')) {
        // do something
    }
    answered = "yes";
}

function waitForInput() {

    // MOUSE CLICK
    $(document).click(function() {
        if (answered == "yes") {
            answered = "no";
            draw(0);
        }
    });

    $('.answer').click(function(e) {
        $('.answer').unbind('click');
        if (answered == "no") {
            calcTime(1);

            e.stopPropagation();
            if ($(this).hasClass('right')) {
                // do something
            }
            else if ($(this).hasClass('wrong')) {
                // do something
            }
            answered = "yes";
        }
    });

    // KEYPRESSES
    $(document).bind('keyup', function(e){
        $(document).unbind('keyup');
        if (answered == "yes") {
            e.stopPropagation();
            keyAns();
        }
        else if ( answered == "no") {
            calcTime(1);    // irrelevant

            if(e.which == 81 || e.keyCode == 81) { // Q
                AAA = '#ansQ';
                e.stopPropagation();
                keyNotAns(AAA);
            }
            else if(e.which == 87 || e.keyCode == 87) { // W
                AAA = '#ansW';
                e.stopPropagation();
                keyNotAns(AAA);
            }
            else if(e.which == 69 || e.keyCode == 69) { // E
                AAA = '#ansE';
                e.stopPropagation();
                keyNotAns(AAA);
            }
            else if(e.which == 82 || e.keyCode == 82) { // R
                AAA = '#ansR';
                e.stopPropagation();
                keyNotAns(AAA);
            }
            else {
            }
            waitForInput();
        }
    });

}
4

4 回答 4

3

每次有按键事件时,您都会重新绑定所有内容。

这意味着如果您按下 10 个键,您将拥有 10 个onclick侦听器。因此,当用户单击时,回调将连续运行 10 次。

您发布的代码不包括对 waitForInput 函数的原始调用,但您只需调用一次,因此您可以从该代码中删除它。

jquery事件的快速介绍:

当你bind,每次该事件发生时(在你放置它的元素上),你提供的回调函数都会运行。

另一个提示是,在更新的 jQuery 版本中,有一个替代绑定命名的one. 它的作用相同,但它只会在第一次运行。尽管在这种情况下,您不需要它。

于 2013-10-03T14:01:42.260 回答
2

您的问题是在您的键绑定中,您正在调用waitForInput.

异步编程需要一些时间来适应,但是 waitForInput 内部的函数所做的是设置事件侦听器,并且每当事件发生时,这些侦听器就会触发。

您看到的问题是,在处理事件后,您正在添加更多事件侦听器,并且下次触发事件时,侦听器将触发多次。

只需waitForInput()从函数中取出这一行,并将其放在代码的底部。然后它只会运行一次,你会没事的。setupEventListeners(为了避免混淆,将其重命名为类似 不会有什么坏处。)

于 2013-10-03T14:01:22.483 回答
1

找到了!

多亏了Scott Mermelstein和ColBeseder,他们对我的解决方案同样无价!他们不仅发现了缺陷,还让我了解了事件绑定是如何工作的。所以谢谢一百万,你们两个!

的确:

  • 绑定被堆叠,因此如果它被触发,它也会过度触发;
  • 然而,waitForinput() 的自我调用确实是不需要的;
  • 还需要一个 e.stopPropagation(),以防止循环使用错误的事件数据,这导致函数将其解释为下一个答案并再次触发自身。

另外:由于懒惰 - 我不觉得有太多的试验和错误 - 我想保持安全,所以我在函数触发时添加了所有 unbind() 作为第一件事。

对于那些感兴趣的人来说,结果完美无缺:

function keyNotAns (A) {
    B = $(A).children('.answer');
    if ($(B).hasClass('right')) {
        // do something
    }
    else if ($(B).hasClass('wrong')) {
        // do something
    }
    answered = "yes";
}

function waitForInput() {
    $(document).unbind('keyup');
    $(document).unbind('click');
    $('.answer').unbind('click');

    // MOUSE CLICKS
    $(document).click(function() {
        if (answered == "yes") {
            answered = "no";
            draw(0);
        }
    });

    $('.answer').click(function(e) {
        if (answered == "no") {
            calcTime(1);
            if ($(this).hasClass('right')) {
                // do something
            }
            else if ($(this).hasClass('wrong')) {
                // do something
            }
            e.stopPropagation();
            answered = "yes";
        }
    });

    // KEYPRESSES
    $(document).bind('keyup', function(e){
        if (answered == "yes") {
            answered="no";
            draw(0);
        }
        else if (answered == "no") {
            if(e.which == 81 || e.keyCode == 81) { // Q
                keyNotAns('#ansQ');
            }
            else if(e.which == 87 || e.keyCode == 87) { // W
                keyNotAns('#ansW');
            }
            else if(e.which == 69 || e.keyCode == 69) { // E
                keyNotAns('#ansE');
            }
            else if(e.which == 82 || e.keyCode == 82) { // R
                keyNotAns('#ansR');
            }
        }
    });
}
于 2013-10-03T16:54:28.373 回答
-1

有两种方法可以找到此类错误。第一个是使用调试器——当你有循环时这可能会很乏味。

第二种方法是记录:写一份所有重要操作的报告/日志,您可以稍后阅读以找出它在过去某个时间点失败的原因。

看看console.log()或一个JavaScript 日志框架

于 2013-10-03T14:00:10.677 回答