jQuery 切换标签时动画功能中断

jQuery animation function breaks when switching tabs

更新: 我在 plunkr 中重现了错误:请参阅 http://plnkr.co/BpYfCNBESUT6ZkiSZHgx

当您执行以下操作时出现问题:

打开 website。刷新网站,当您看到页面正在浏览器选项卡中加载时,when you see the spinner in the tab


切换到浏览器中的另一个选项卡。如果它没有发生。再试一次。如果按照所说的去做,您很可能会看到这个:

你可能会说,this is not such a big deal, you have to be real fast to let this error happen。然而,想象一下连接速度较慢的人,他转到浏览器中的另一个选项卡,继续观看他的 YouTube 视频,同时网站正在加载。当他回来时,他只看到页面一直在加载。


让我们假设这个 animation 代码:

$pageloaderbar.animate({
    width: "46%"
}, {
    duration: 700,
    complete: function () {
        $scope.continue();
    }
});

当第一个 animation 完成时,它会调用一个名为 $scope.continue(); 的新函数。看起来像这样:

$scope.continue = function () {
    $timeout(function () {
        $pageloaderbar.animate({
            width: "100%"
        }, {
            duration: 500,
            complete: function () {
                $scope.PageIsLoading = false;
            }
        });
    });
}

问题是,当用户在浏览器中切换选项卡时,在 $pageloaderbar.animate$scope.continue 之间,$plageloaderbar.animate 函数永远不会到达 complete 函数。浏览器控制台显示如下错误(Chrome)

我的问题是,如何查看用户是否在网站上 active?或者,即使用户不是 browser tab 上的 active,我如何仍然执行该功能?

因为好像没有人带遮阳篷,所以我自己想了一个小办法。但是,如果有人仍然可以解释为什么 animation 在切换标签时中断,我很高兴。

解决方法非常简单,我只需添加这段代码。

complete: function () {
    if(document.hidden) {
        $(window).on("blur focus", function () {
            $scope.continue();
        });
    } else {
        $scope.continue();
    }
}

而不是:

complete: function () {
    $scope.continue();
}
 $scope.continue = function () {
        $timeout(function () {
            $pageloaderbar.animate({
                width: "100%"
            }, {
                duration: 500,
                complete: function () {
                    $scope.PageIsLoading = false;

                    $("body").css("overflow", "auto");
                    $pageloaderwrap.addClass("page-loader-finished");

                    $scope.pageReady();
                }
            });
        });
    }

    var $pageloaderwrap = $(".page-loader-wrap");
    var $pageloader = $(".page-loader");
    var $pageloaderbar = $(".page-loader .page-loader-bar");

    $("body").css("overflow", "hidden");


    $pageloaderbar.animate({
        width: "46%"
    }, {
        duration: 700,
        complete: function () {
            if (document.hidden) {
                $(window).on("blur focus", function () {
                    $scope.continue();
                });
            } else {
                $scope.continue();
            }
        }
    });

尝试在调用 $pageloaderbar.animate 之前定义您的 continue 函数。这可能不是主要问题,但总是有可能因此而出现问题。

你的解决方案只是一个补丁,不是真正的解决方案,看起来也不是很好。即使它解决了你的问题,你也必须找到某种方法来防止这个错误。

我强烈建议你离开jquery。此类问题通常来自 jquery - angular 不兼容。

在 chrome 的较新版本中,这与选项卡的可见性有关,您的功能因此而中断。您可以使用可见性 API 来了解该选项卡是否对用户可见。

请看一下我发现的 link:

http://dystroy.org/demos/vis-en.html

这是由 jQuery animate 函数引起的,该函数将动画选项对象传递给名为 speed 的函数。此函数检查 document 是否为 hidden - 如果选项卡处于非活动状态,则为 hidden。如果隐藏,(或者fx.off设置为true),所有动画持续时间设置为0.

您可以在 plunkr 的 jQuery 文件中的 7137 行看到这个。

    if ( jQuery.fx.off || document.hidden ) {
    opt.duration = 0;

由于动画现在没有持续时间,它变为同步,因此您的 complete 函数在调用 animate 之后出现的事实是一个问题。

要解决此问题,您需要将 complete 函数声明移到对 animate.

的调用上方