如何在更改事件处理程序中追加后获取jQuery单击事件

时间:2014-12-24 00:14:41

标签: jquery events

我有以下文件:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta charset="UTF-8">
    <title>Test</title>
    <script src="https://code.jquery.com/jquery-2.1.1.js"></script>
</head>
<body>
    <div id="alert"></div>
    <input type="text" id="input"></br>
    <span id="span">Span</span>

<script>
    $(function() {
        $('#input').on('change', function() {
            console.log('change');
            $('#alert').append('<div>An alert</div>');
        });
        $('#span').on('click', function() {
            console.log('click');
        });
    });
</script>
</body>
</html>

单击span并运行click事件处理程序。

更改输入并更改事件处理程序。

更改输入并单击跨度(不保留输入 - 例如没有标签输出,也没有单击其他位置)并且更改事件处理程序运行但单击事件处理程序不运行。

如果我从更改事件处理程序中删除了append,然后更改输入并单击span,两个事件处理程序都会运行,因此append会以某种方式干扰click事件。

如何在更改事件处理程序附加元素后触发click事件?

这是引发问题的最小代码。在实际情况中,有多个输入,并且跨度的样式看起来和行为就像一个按钮。输入上的更改事件处理程序验证值,如果它们无效则添加警报。通常,输入在不单击范围/按钮的情况下进行更改,但编辑输入然后单击范围/按钮,同时输入焦点仍在输入上,在这种情况下,我希望两个事件处理程序都能运行。

在进一步调查中,我发现问题在于如何生成事件。

每个DOM Level-2:点击元素上的指针设备按钮时发生click事件。单击被定义为同一屏幕位置上的mousedown和mouseup。这些事件的顺序是:

mousedown
mouseup
click

如果没有更改事件处理程序中的'append',当我编辑输入时,请点击我看到的范围:

  1. mousedown on span
  2. 更改输入
  3. mouseup on span
  4. 点击span
  5. 但是,通过更改事件处理程序中的追加,我看到:

    1. mousedown on span
    2. 更改输入
    3. 输入上的mouseup
    4. 在后一种情况下,mousedown和mouseup事件具有相同的坐标(如果我小心点击时不移动鼠标):它们都是span元素边界内和输入元素外部的坐标。尽管如此,在Firefox和Chrome中,mouseup与input元素而不是span元素相关联。

      所以,我的问题变成:为什么mouseup事件与input元素而不是span元素相关联,当它的坐标在span元素的边界内而不在input元素的边界内时?

5 个答案:

答案 0 :(得分:2)

可以通过多种方法来解决此问题。这完全取决于UI演示。根据设计,您还可以考虑其他解决方法。截至目前,我可以想到可以解决这个问题的三件事:

  1. 将警报div设置为高度并使其可垂直滚动。这样做会阻止您的跨度位置变化,并会触发这两个事件。 e.g

     <div id="alert" style="height: 100px; overflow-y: scroll;"></div>
  2. 或者您可以稍微更改您的JavaScript以满足您的目的。以下是代码片段(已修改评论),其中包含更改以满足您的需求。

    $(function() {
        var isMouseDownOnSpan = 0;  // flag variable added to track whether user clicked on the span.
        $('#input').on('change', function() {
            console.log('change');
            $('#alert').append('<div>An alert</div>');
            // If user tries to click on the span then trigger the click event manually.
            if(isMouseDownOnSpan){
                $('#span').trigger('click');                
            }
        });
    
        // Bind mousedown event and set the flag value true. This ensures that the user clicked on the span.
        $('#span').on('mousedown', function(e) {
            isMouseDownOnSpan = 1;
        });
    
        $('#span').on('click', function() {
            isMouseDownOnSpan = 0; // Reset flag value once the click event is fired.
            console.log('click');
        });
      });
    
  3. 或者上述任何一个都不适合你,那么你可以设计你的跨度并给它一定的宽度和高度,这样即使在追加警告div后,用户的鼠标也在跨度边界内。我知道这不是一个永久的解决方案,但它仍然可以最大限度地减少现实生活场景中的错误变化。 ;)

答案 1 :(得分:0)

我保存了您的代码并在浏览器中运行并且可以正常运行。为什么你认为它没有?你在检查控制台输出吗?

答案 2 :(得分:0)

在您的更改事件处理程序中添加$('#span')。click()

$(function() {
    $('#input').on('change', function() {
        console.log('change');
        $('#alert').append('<div>An alert</div>');
        $('#span').click();
    });
    $('#span').on('click', function() {
        console.log('click');
    });
});

答案 3 :(得分:0)

我弄清楚我的问题是什么:

当我添加到div时,文档布局会发生变化。我将光标放在跨度上并按下鼠标左键。这会导致输入失去焦点,从而触发更改事件。 change事件处理程序将一个div附加到#alert div。这会将屏幕下方的所有内容推到屏幕下方。然后我释放了鼠标按钮,没有移动它。但是鼠标不再超出范围 - 由于布局已更改,现在它已经在输入上,因此mouseup事件将输入作为其目标,而不是跨度。

即使鼠标没有移动,屏幕布局也发生了变化,因此鼠标离开了跨度并输入了输入。跨度看到没有鼠标的mousedown,所以没有点击。输入看到没有mousedown的mouseup,所以也没有点击那里。

我的错误是认为因为我没有移动鼠标,所以鼠标仍然应该超出范围。

如果我在跨度之后放置警报div,那么编辑输入并单击跨度按预期工作,但这不是我想要的屏幕布局。

我想如果我将警报div留在顶部,我需要在更改事件处理程序中执行的操作是将消息添加到警报div,这会将范围向下移动,然后将鼠标向下移动以使其保持静止在跨度。然后,当用户释放鼠标按钮时,它仍然会跨越跨度,跨度可能(我希望)接收到点击事件。

答案 4 :(得分:-2)


     $(function() {
            $('#input').on('change', function() {
                console.log('change');
                $('#alert').append('An alert', function(){
                      $('#span').on('click', function() {
                         console.log('click');
                      });
                });
            });
            $('#span').on('click', function() {
                console.log('click');
            });
        });