为什么使用ngRoute第二次加载时此画布动画挂起

Why this canvas animation hangs when loaded for a second time with ngRoute?

本文关键字:布动画 动画 挂起 ngRoute 第二次 加载 为什么      更新时间:2023-09-26

问题

我正在使用一个空间入侵者画布动画作为我的404未找到页面。当用户第一次被重定向到它时,它工作得很好,但如果用户第二次被重定向,动画就会挂起。


Demo

我创建了一个Plunker示例来展示这个问题。页面从加载home.html的/位置开始;重定向至/404〃;,则位置将改变为CCD_ 2并且将加载404.html。游戏动画将顺利运行。

但是,如果返回/(单击链接(并再次返回/404,则动画将挂起。此外,每秒帧数将从60帧/秒下降到10帧/秒。


代码

这个演示是用AngularJS构建的,我使用ngRoute切换页面,如下所示:(没有什么特别的(

$routeProvider.
    when('/', {
        templateUrl: 'partials/home.html',
        controller: 'HomeCtrl'
    }).
    when('/404', {
        templateUrl: 'partials/404.html',
        controller: '404Ctrl'
    });

home.html只包含指令,404.html包含画布元素:

<canvas id="game-canvas" width="600" height="400"></canvas>

角度控制器启动调用initInvaders404();的动画。这个函数在handle-game.js中定义。game.jss完成画布动画代码,该代码在加载404.html页面后立即执行。


我已经试过了

首先猜测:问题可能与画布使用其ID启动有关。当我重新创建404.html时,动画附加了以前的ID,但没有更新的ID。为了测试这一点,我创建了另一个Plunker,并用类似的方法测试了另一动画(蓝色矩形移动(。它运行良好,所以也许这不是问题所在。

再次猜测:附加到画布的动画代码只执行一次,这就是为什么它第二次不起作用。为了测试这一点,我在控制器中放置了game.js和handle-game.js代码。不幸的是,同样的问题。Plunker

第三种猜测:ngRoute扰乱了画布元素。为了测试这一点,我将canvas元素放置在ngView之外,并控制ngShow来隐藏/显示画布。通过这种方法,问题得到了解决。initInvaders404();可以被多次调用,但它将始终集中在同一个元素中,并且永远不会被重新创建。Plunker。


问题

为什么这个动画不能执行两次?

注意1:我不想要一个变通的解决方案(我已经在第三次猜测中找到了一个(。我希望将画布元素保留在404.html文件中。

注意2:这个问题是而不是一个"请调试我的代码";(因为game.js有2000行代码(。我想了解的是,是否有画布属性或ngRoute行为可能导致这种情况。

我发现可以第二次执行动画,但前提是第一个动画已经完成。在这种情况下,在游戏以onWin()onLoose()事件结束之后。

当ngRoute更改视图时,画布元素被破坏,但游戏循环仍然在后台运行(正如我使用一些console.log()所确认的那样(。当我试图将相同的游戏循环附加到相同的画布id时,它会挂起。

使用的解决方法是捕获$locationChangeStart事件并在画布销毁之前停止动画。当我需要第二次执行游戏时,它会运行:Plunker。

获取$locationChangeStart事件:

ctrls.controller(
  'MyRootController',
  function($location, $rootScope) {
    $rootScope.$on("$locationChangeStart", function(event, next, current) { 
        var contains404 = current.includes("404");
        if (contains404) { // if current is 404, next will be something else
          stopInvaders404(); // code to stop the game loop before destroying the canvas
        }
    });
  }
);

然而,对于第三方动画,最简单的解决方案是将画布放置在ngView之外并控制其可见性:Plunker,它不涉及更改动画代码(就像我对stopInvaders404()所做的那样(。