jQuery单击工作一次,而不是两次

jQuery Click Working Once, not Twice

本文关键字:两次 单击 jQuery 一次 工作      更新时间:2023-09-26

在函数的作用域中,我加载HTML以通过AJAX在Bootstrap模式中显示。AJAX加载是昂贵的,我想缓存它加载的内容。但是,HTML中表的行可以动态更改,并且需要绑定到这些行的单击侦听器。

除了发布一些代码,我不知道如何最好地解释这种情况。

Fiddle:http://jsfiddle.net/vvc1j1eh/1/

因此,最大的问题是,为什么第一次加载点击在第一次就可以工作,而在我尝试重复使用缓存内容之后就不能了?还有为什么第二次加载作用域每次都会点击工作?

编辑:更好地解释问题

加载页面,然后单击"加载"以显示对话框。如果单击某一行,则会弹出一个警告,其中包含您单击的行。单击对话框之外的任何位置将其隐藏,然后再次单击"加载"。这一次,当您单击行时,不会弹出警报消息。

如果对"使用右侧作用域加载"按钮执行完全相同的过程,则在第二次显示对话框时单击行时仍会收到警报。

委派:

很难在示例中进行解释,但内容"文档"页面也是通过AJAX与多个页面一起动态加载的。当用户浏览Web应用程序时,会显示和隐藏这些多个页面,所以我不能只将全局侦听器绑定到文档。

这将是我在尝试授权时所做的最接近的事情:

var $data = expensiveAjaxLoad();
$data.on('click', 'tbody td', function() {
    alert($(this).html());
});
$('#load').click(function() {
    addRowsAndListeners($data);
    $('#content').html($data);
    $('#modal').modal('show');
});

它仍然没有回答的大问题,这就是为什么事件第二次不绑定?它们第一次绑定,在我进行调试时,作用域变量$data似乎没有任何更改。

堆栈代码段:

$(document).ready(function() {
  //Scope of the function
  //$data works the first time, but additional row
  //clicks don't register events
  var $data = expensiveAjaxLoad();
  $('#load').click(function() {
    addRowsAndListeners($data);
    $('#content').html($data);
    $('#modal').modal('show');
  });
  //Why does this work?
  $('#load-scope').click(function() {
    var $better = expensiveAjaxLoad();
    addRowsAndListeners($better);
    $('#content').html($better);
    $('#modal').modal('show');
  });
});
function expensiveAjaxLoad() {    
  var html = [];
  html.push('<table><tbody>');
  html.push('</tbody></table>');
  return $(html.join(''));
}
function addRowsAndListeners($data) {
  var html = [];
  //Rows can vary, don't need to recreate the entire table
  for (var i = 0; i < 5; i++) {
    html.push('<tr><td>Row ');
    html.push((i + 1));
    html.push('</td></tr>');
  }
  $('tbody', $data).html(html.join(''));
  //Something here is not binding correctly
  $('tbody td', $data).click(function() {
    alert($(this).html());
  });
}
<!DOCTYPE html>
<html>
    <head>
        <title>Test</title>
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
    </head>
    <body>
        <div>
            <h1>Hello Alice</h1>
            <button id="load">Load</button>
            <button id="load-scope">Load With Right Scope</button>
        </div>
        <div id="modal" class="modal fade">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h4 class="modal-title">Modal Title</h4>
                    </div>
                    <div id="content" class="modal-body">
                    </div>
                </div>
            </div>
        </div>
    </body>
</html>

更新:

这是一个新的Fiddle,它使用了我当前生产代码的最小数量。

http://jsfiddle.net/0vb2psv4/1/

您需要对文档使用事件委派,因为存在动态创建的元素。同时移动文档就绪中的点击事件绑定,而不是函数addRowsAndListeners()

工作示例

 $(document).on('click','tbody td',function() {
        alert($(this).html());
    });

更新:使用您的原始代码,将其委托给内容(表或模型体的容器),因为您的表也是动态

$("#content").on('click', 'tbody tr', function(e) {
        e.preventDefault();
            var $this = $(this);
            if ($this.hasClass('selectable')) {
                $this.toggleClass('success');
            }
        });

更新的fiddle:

我能够通过更改$('#load').click():JSFiddle DEMO来实现您想要的功能

$('#load').on("click", function() { //changed to on("click")
    addRowsAndListeners($data);
    $('#content').html($data);
    $('#modal').modal('show');
    //remove the on("click") and set up a new on("click") to just show the modal     
    $('#load').off("click").on("click", function() { 
        $('#modal').modal('show');
        //you could add additional logic in here if you need to conditionally redo the ajax call
    });
});

因为您正在添加行,jQuery没有意识到它们。您需要委托点击事件-

$(document).on('click', 'tbody td', function() {
    alert($(this).html());
});