通过AJAX加载内容后,jQuery无法工作。

67
这个页面上,我有一个jQuery弹出窗口和可调整大小的缩略图。当我鼠标悬停在缩略图上时,图像会完美地调整大小。同时,当我单击页脚中的大黄色电视按钮“QuickBook TV”时,弹出窗口也会完美地显示。
然而,当我单击“下一个”或“上一个”按钮时,使用AJAX加载新内容,我的jQuery对于弹出窗口或缩略图图像不再起作用。我已经搜索了多个论坛,寻找有关此问题的信息,但由于对jQuery的知识有限,我无法理解需要做什么。
以下是弹出窗口的jQuery:
$(document).ready(function() {

        $(".iframe").colorbox({ iframe: true, width: "1000px", height: "500px" });
        $(".inline").colorbox({ inline: true, width: "50%" });
        $(".callbacks").colorbox({
            onOpen: function() { alert('onOpen: colorbox is about to open'); },
            onLoad: function() { alert('onLoad: colorbox has started to load the targeted content'); },
            onComplete: function() { alert('onComplete: colorbox has displayed the loaded content'); },
            onCleanup: function() { alert('onCleanup: colorbox has begun the close process'); },
            onClosed: function() { alert('onClosed: colorbox has completely closed'); }
        });

        //Example of preserving a JavaScript event for inline calls.
        $("#click").click(function() {
            $('#click').css({ "background-color": "#f00", "color": "#fff", "cursor": "inherit" }).text("Open this window again and this message will still be here.");
            return false;
        });
    });

这是缩略图 jQuery 插件。

$(function() {

var xwidth = ($('.image-popout img').width())/1;
var xheight = ($('.image-popout img').height())/1;

$('.image-popout img').css(
        {'width': xwidth, 'height': xheight}
); //By default set the width and height of the image.

$('.image-popout img').parent().css(
        {'width': xwidth, 'height': xheight}
);

$('.image-popout img').hover(
    function() {
        $(this).stop().animate( {
            width   : xwidth * 3,
            height  : xheight * 3,
            margin : -(xwidth/3)
            }, 200
        ); //END FUNCTION

        $(this).addClass('image-popout-shadow');

    }, //END HOVER IN
    function() {
        $(this).stop().animate( {
            width   : xwidth,
            height  : xheight,
            margin : 0
            }, 200, function() {
                $(this).removeClass('image-popout-shadow');
    }); //END FUNCTION

    }
);

});
9个回答

128

jQuery 选择器会选择在代码执行时在 DOM 中存在的匹配元素,并且不会动态更新。当你调用一个函数,比如 .hover() 来添加事件处理程序时,它只会将其添加到那些元素上。当你进行 AJAX 调用并替换页面的某个部分时,你会删除那些带有绑定事件处理程序的元素,并用新元素替换它们。即使这些元素现在匹配了该选择器,它们也不会得到已经执行的绑定事件处理程序,因为执行绑定已经完成。

事件处理程序

特别针对事件处理程序(比如 .click()),你可以使用事件委托来解决这个问题。基本原则是将事件处理程序绑定到静态元素(页面加载时存在,永远不会被替换),该元素包含所有动态(通过 AJAX 加载)的内容。关于事件委托,你可以在 jQuery 文档 中了解更多信息。

对于你的 click 事件处理程序,更新后的代码应该像这样:

$(document).on('click', "#click", function () {
    $('#click').css({
        "background-color": "#f00",
        "color": "#fff",
        "cursor": "inherit"
    }).text("Open this window again and this message will still be here.");
    return false;
});

这会将事件处理程序绑定到整个文档(因此在页面卸载之前永远不会被删除),该处理程序将对具有id属性为click的元素上的click事件做出反应。理想情况下,您应该使用更接近于DOM中动态元素的东西(也许是在您网页上始终存在并包含所有网页内容的<div>),这样可以提高一些效率。

然而,当您需要处理.hover()时,问题就来了。在JavaScript中没有实际的hover事件,jQuery只是提供了该函数作为方便的缩写,用于将事件处理程序绑定到mouseentermouseleave事件。不过您可以使用事件委托:

$(document).on({
    mouseenter: function () {
        $(this).stop().animate({
            width: xwidth * 3,
            height: xheight * 3,
            margin: -(xwidth / 3)
        }, 200); //END FUNCTION

        $(this).addClass('image-popout-shadow');
    },
    mouseleave: function () {
        $(this).stop().animate({
            width: xwidth,
            height: xheight,
            margin: 0
        }, 200, function () {
            $(this).removeClass('image-popout-shadow');
        }); //END FUNCTION

    }
}, '.image-popout img');

jQuery插件

上述已涵盖事件处理程序绑定。但这还不是全部,你还在初始化一个jQuery插件(colorbox),并且没有一种方法可以将其委派给元素。当你加载了AJAX内容时,你需要简单地再次调用那些行;最简单的方法是将它们移动到一个单独的命名函数中,然后在两个位置(页面加载和AJAX请求的success回调函数中)都可以调用该函数:

function initialiseColorbox() {
    $(".iframe").colorbox({
        iframe: true,
        width: "1000px",
        height: "500px"
    });
    $(".inline").colorbox({
        inline: true,
        width: "50%"
    });
    $(".callbacks").colorbox({
        onOpen: function () {
            alert('onOpen: colorbox is about to open');
        },
        onLoad: function () {
            alert('onLoad: colorbox has started to load the targeted content');
        },
        onComplete: function () {
            alert('onComplete: colorbox has displayed the loaded content');
        },
        onCleanup: function () {
            alert('onCleanup: colorbox has begun the close process');
        },
        onClosed: function () {
            alert('onClosed: colorbox has completely closed');
        }
    });
}

非常感谢你的帮助,大问题——图像缩略图问题已经解决了。但是Colorbox弹出问题仍然存在。你能否指导我如何在页面加载和Ajax请求中调用它? - Awais Imran
1
@AwaisImran 将它移动到一个单独的函数中(如我答案后半部分所建议的),然后调用该函数替换你的$(document).ready()函数中的这些行来处理页面加载。在jQuery中的所有AJAX函数都需要一个(可选的)成功回调函数,在响应成功时执行。然后你只需要调用那个函数; 如果你在问题中包含了相关的AJAX调用,我可以更具体地解释。 - Anthony Grist
嘿,安东尼,我已经解决了弹出窗口的问题。我将这个脚本“$(document).ready(function() {”更改为这一行“$(document).on('mouseover', '.iframe', function() {”,现在它对我来说运行良好。非常感谢你的支持。我希望我能像你一样成为jQuery专家 :) - Awais Imran
1
@pXdty 不,这种情况下行不通。代码会在没有错误的情况下运行,但是它绑定了一个静态事件处理程序;它只影响在代码运行时存在的元素。这里的整个重点是当代码运行时所有与“selector”匹配的元素都不存在,因此需要委托事件处理程序。 - Anthony Grist
@Anthony Grist 同感!我忘记了“return false;”。谢谢! - GTodorov
显示剩余3条评论

30

之前我也遇到了同样的问题,后来找到了适合我的解决方案。所以如果将来有人尝试这个方法并且可以告诉我是否正确,因为我能找到的所有解决方案都比这个复杂一些。

正如Tamer Durgun所说,我们也将在ajaxStop中放置您的代码,这样每次任何事件通过ajax完成时,您的代码都将被恢复。

$( document ).ajaxStop(function() {

//your code

}

对我有用 :)


我尝试了所有方法:.done,.complete,.always,复制成功,我的意思是全部尝试了。 除了这个之外什么都不行。非常感谢 :) - jechaviz
很高兴能提供帮助 :) - Angad Arora
1
谢谢@Angad,这真的有效。不知道为什么这还没有被接受为正确答案。 - Sushil Kumar Singh
1
这似乎是有效的。然而,值得指出的是,ajaxStop(...) 只有在你实际上拥有一个 ajax 组件时才会被触发(显然)。当你的整个页面最初加载时,它不会被触发。换句话说,你可能最终需要 $(document).read(function(){/*your code*/})$(document).ajaxStop(function(){/* your code again*/}) 两者都需要。 - RayLuo
你找到了不重复代码的方法吗? - stoneshaq
尝试了不同的方法来自动选择和触发通过ajax加载的元素上的事件,这是我得到的解决方案 (已解决) https://dev59.com/pWox5IYBdhLWcg3wDgIz#68383274 - Akashxolotl

4
// EXAMPLE FOR JQUERY AJAX COMPLETE FUNC.
$.ajax({
    // get a form template first
    url: "../FPFU/templates/yeni-workout-form.html",
    type: "get",
    success: function(data){
        // insert this template into your container
        $(".content").html(data);
    },
    error: function(){
        alert_fail.removeClass("gizle");
        alert_fail.addClass("goster");
        alert_fail.html("Template getirilemedi.");
    },
    complete: function(){
        // after all done you can manupulate here your new content
        // tinymce yükleme
        tinymce.init({
            selector: '#workout-aciklama'
        });
    }

3
当你替换内容时,事件处理程序会丢失。当你设置hover事件时,jQuery正在设置它们在当前页面上的事件。因此,当你用ajax替换它们时,这些事件与那些元素没有关联,因为它们是新的。
要解决这个问题,你可以再次调用绑定它们的函数,或者像这个答案中使用$(document).on在文档上设置事件处理程序。
这样,事件就被设置在文档上,任何新元素都将调用该事件。

1
您可以使用jQuery的delegate()方法,该方法将处理程序附加到与选择器匹配的一个或多个元素的所有事件上,现在或将来,基于一组特定的根元素。在我的情况下,它按预期工作。
使用delegate()方法后,这个$(selector).click(function(e){}变成了这个: $( "body" ).delegate( "selector", "click", function(e) {} 希望这能有所帮助;)

0

我来晚了,但我会结合两个答案。对于我的特定需求,有效的方法是在complete中加入ajaxstop。

complete: function () {
     $( document ).ajaxStop(function() {
         //now that all have been added to the dom, you can put in some code for your needs.
         console.log($(".subareafilterActive").get().length)

     })
}

0

在从某个地方检索数据后,您可以使用jQuery ajax的complete函数,它将在ajax完成后查看更新的元素。


added an example below - Tamer Durgun

0

只是一个替代品。

$(window).on('load', _ => {
    // some jQuery code ..
})

这将任何委托处理程序绑定到窗口。它将在窗口完全加载后触发,包括所有图形/包含/钩子/请求,而不仅仅是DOM。

$(document).ready(_ => ... 保留事件在仅DOM准备就绪后触发,这不适用于通过AJAX动态加载的内容。您可以像@Anthony Grist在他的答案中所解释的那样将特定元素定义为已完全加载时运行函数或任何事件,或者像上面所示将您的加载事件绑定到窗口。

https://api.jquery.com/load-event/
https://api.jquery.com/on/#on-events-selector-data-handler


0

这对我有用,

而不是:

$(document).ready(function(){
//code
});

我做了:

$(document).on('mouseenter', function(){
//code
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接