【问题标题】:jQuery: click() triggers twice with dynamic contentjQuery:click() 使用动态内容触发两次
【发布时间】:2014-03-02 19:51:57
【问题描述】:

我基本上是通过 ajax 将数据库中的内容加载到 div 中。然后,点击这些内容片段应该会重新加载新内容。

ajax 请求被初始化为我在开头调用的类中的一个方法:

function Request(tag1, tag2, tag3) {
    this.tag1 = tag1,
    this.tag2 = tag2,
    this.tag3 = tag3
}
Request.prototype = {
    ajaxCategoryRequest: function () {
        $.ajax({
            type: "GET",
            url: "request2.php",
            data: "tag1=" + this.tag1 + "&tag2=" + this.tag2 + "&tag3=" + this.tag3,
            success: function (data) {
                var jdata = $.parseJSON(data);
                //Frage ausgeben
                $("h1.question").html(jdata[0]);
                //Tiles ausgeben
                for (var i = 1; i < jdata.length; i++) {
                    $("#tiles").append(
                        '<div class="category" id="' + jdata[i].type + '" data-owntag="' + jdata[i].owntag + '" data-description="' + jdata[i].description + '"><img src="' + jdata[i].imageurl + '" alt="' + jdata[i].name + '"/><div class="ctitle">' + jdata[i].name + '</div></div>'
                    );
                }
            }
        });
    }
};
var searchtype = new Request("", "", "");
searchtype.ajaxCategoryRequest();

然后单击上面创建的 div 之一应该会启动一个新请求:

    $("#tiles").on('click', '.category', function () {
        var tag1 = "newtag";
        var tag2 = "newtag";
        var tag3 = "newtag";
        //remove old content
        $('.category').remove();
        //start new request
        var nextrequest = new Request(tag1, tag2, tag3);
        nextrequest.ajaxCategoryRequest();
    });
});

基本上一切正常,内容已加载,如果我单击一个 div,它确实会触发一个新请求,但出现错误,它被触发了两次。因此,每个新加载的元素都会出现两次。

我搜索了一下,我认为是由于ajax请求中的打印循环,每次都将click函数绑定到div。我读了很多关于 .unbind("click") 和 .bind() it 或类似的内容( .off() ),但对我没有任何帮助。也许这个问题还有其他解决方案?

【问题讨论】:

  • 顺便说一下,你可以将jQuery中的AJAX调用压缩到$.get(url, function(data){ ...data stuff here... }).success(function(data){...});。趋向于不那么阻塞并且更容易阅读(imo)。
  • 事件监听器究竟是什么时候绑定的?请求后是否再次绑定?
  • @Bergi 我是一个初学者,老实说我不太确定,但我认为每次 AJAX 调用打印出一个新的“.category” div 时都会受到约束。 .on() 是在请求​​之后编写的。也许整个代码都有帮助,mwmg.no-ip.biz/test/index2.php
  • 是的,它确实有帮助。您尚未在帖子中显示错误代码...
  • @Bergi 您认为错误在哪里,所以我可以将其包含在帖子中?

标签: javascript jquery ajax dynamic click


【解决方案1】:

触发了两次

实际上,并非如此。将您的console.log("Mouseclick"); 放在点击监听器的第一行,每次点击您只会看到一次。

$("#tiles").on('click','.category',function(e){
   // …
   //remove old elements
   $('.category').fadeOut(200,function(){
       console.log("Mouseclick");
       $(this).remove();
       //start request when animation completed
       var nextrequest = new Request(tag1,tag2,tag3);
       nextrequest.ajaxCategoryRequest();
   });
});

动画是你的问题。对fadeOut 的回调为每个 .category 元素调用 - 这就是你的$(this).remove() 起作用的原因(因为this 只是一个&lt;div&gt; 元素)。

因此,您实际上是针对已删除的每个类别开始一个新请求,这当然不是您想要的。您可以做的是将请求移出动画回调,然后它会立即开始。没有竞争条件,但是 - 当 ajax 速度超过 200 毫秒时 - 可能会出现新类别出现而旧类别仍在淡出的情况。

如果你想防止这样的故障,你需要在所有动画回调完成后找到一种方法来触发 ajax。幸运的是,.promise method 正是这样做的——它返回一个保证只解析一次的承诺,您可以在事件队列的末尾添加回调:

$("#tiles").on('click','.category',function(e){
   console.log("Mouseclick");
   // …
   // remove old elements
   $('.category').fadeOut(200,function(){
       $(this).remove();
   }).promise().done(function() {
       // start request once when all animations completed
       var nextrequest = new Request(tag1,tag2,tag3);
       nextrequest.ajaxCategoryRequest();
   });
});

如果你想缩短 ajax 请求完成的时间,你甚至可以很容易地并行运行动画和请求,添加一个回调 when 两个任务都完成了:

function categoryRequest(data) {
    return $.ajax({
        type: "GET",
        url: "request2.php",
        data: {tag1: tag1, tag2: tag2, tag3: tag3},
        dataType: "json" // invokes $.parseJSON automatically
    });
}
function outputData(jdata) {
    //Frage ausgeben
    $("h1.question").html(jdata[0]);
    //Tiles ausgeben
    for (var i = 1; i < jdata.length; i++) {
         $("#tiles").append(
             '<div class="category" id="' + jdata[i].type + '" data-owntag="' + jdata[i].owntag + '" data-description="' + jdata[i].description + '"><img src="' + jdata[i].imageurl + '" alt="' + jdata[i].name + '"/><div class="ctitle">' + jdata[i].name + '</div></div>'
         );
    }
}

//Erster Aufruf
categoryRequest("", "", "").done(outputData);

// Weitere Aufrufe bei click
$("#tiles").on('click','.category',function(e){
    console.log("Mouseclick");
    //define next request variables (tags)
    var stage = $(this).attr('id');
    var owntag = $(this).data("owntag");
    var tag1 = "", tag2 = "", tag3 = ""; 
    if (stage == 'searchtype')
        tag1 = owntag;
    else if (stage == 'category')
        tag2 = owntag;
    else if (stage == 'subcategory')
         tag3 = owntag;
    else
         console.log("No valid (stage)type defined");

    var removed = $('.category').fadeOut(200,function(){
        $(this).remove();
    }).promise();
    var request = categoryRequest(tag1,tag2,tag3);
    $.when(request, removed).done(function(requestResults) {
        outputData(requestResults[0]);
    });  
});

【讨论】:

  • 哇。谢谢!我尝试了第一个解决方案,它对我有用(尽管我必须将 .remove() 移动到 .promise() 的回调中)。那我试试第二种方法
  • 你的意思是当你有.promise() 时没有调用fadeOut 回调?这很奇怪。
  • 我不确定,是什么问题,但我发布了解决方案。
【解决方案2】:

使用one method 只触发一次功能。

$("#tiles").one('click','.category',function(){

【讨论】:

    【解决方案3】:
    $("#tiles").off('click').on('click','.category',function(){
    

    【讨论】:

    • 我已经尝试过了,但它对我不起作用。也许是因为 .click 绑定到“.category”?我真的是 jQuery 新手
    • 您可以删除'.category'参数
    【解决方案4】:

    我是这样解决的

    $('.category').fadeOut(200).promise().done(function(){
                   //start request when animation completed
                   $(".category").remove();
                   var nextrequest = new Request(tag1,tag2,tag3);
                   nextrequest.ajaxCategoryRequest();
               });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多