角度加载条和图像/视图/状态加载

时间:2015-10-03 14:41:46

标签: angularjs angular-ui-router imagesloaded

我正在使用ui-router作为我的角应用程序。我有一些包含图像的视图。我希望角度加载条也可以在这些图像加载完成后进行跟踪。或者更一般地说,直到视图完成渲染。

当我偶然发现post关于如何使用angularJS进行搜索引擎优化时,它表明我们必须创建每个“页面”的静态html快照,并将它们提供给搜索引擎机器人,以便可以对它们进行爬网。为此,我们必须使用无头浏览器爬行应用程序中的所有页面,并将html存储到将要提供的文件中。但是,由于角度必须加载ajax和所有的视图,我们必须等待我们的页面加载,然后存储无头浏览器的HTML。否则我们会得到空视图的空html。

我写了一个小脚本,可以检查我们的视图的就绪状态。当$ rootScope.status属性等于'ready'时,我知道我可以存储我的无头浏览器的html,因为它已经完成加载。

    <Window x:Class="CountDown.CountDownDisplay"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:CountDown"
        mc:Ignorable="d"
        Title="CountDownDisplay" Height="768" Width="1024" WindowState="Maximized" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
    <Grid Name="grid1">

        <Image x:Name="vwbImage" Source="matematickyproud2015.png"/>

        <Viewbox x:Name="vwbTime" Visibility="Hidden">
            <TextBlock x:Name="txbTimeToEnd" Margin="2" Text="01:30:00" HorizontalAlignment="center" VerticalAlignment="center"/>
         </Viewbox>

    </Grid>
</Window>

然后,在我们的每个控制器中,我们必须调用

var app = angular.module("app", ["ui.router", 'ngAnimate','angular-loading-bar','angular-images-loaded','angular-google-analytics']);

app.run(['$rootScope', function($rootScope){

    $rootScope.loadingCount = 0;
    $rootScope.changeSuccess = false;

    $rootScope.ready = function(){
        $rootScope.loadingCount--;
        if (($rootScope.loadingCount == 0) && ($rootScope.changeSuccess == true)){
            $rootScope.status = 'ready';
        }
    };

    $rootScope.loading = function(){
        $rootScope.loadingCount++;
        $rootScope.status = 'loading';
    };

    $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
        $rootScope.loadingCount = 0;
        $rootScope.changeSuccess = false;
    });

    $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
        $rootScope.changeSuccess = true;
    });

    $rootScope.$on("$viewContentLoading", function(){
        $rootScope.loadingCount++;
    });

    $rootScope.$on("$viewContentLoading", function(){
        $rootScope.loadingCount--;
    });

}]);

当控制器准备就绪时

$rootScope.loading();

有了这个,我们将能够检查我们所有的控制器是否都呈现了他们的观点。它现在不是超级优雅,但是它起到了作用。

此脚本可以与angular-load-bar很好地集成,因为它可以跟踪整个应用程序的准备情况。进度条可以是该进度的指标。这样做的缺点是它与角度加载条跟踪XHR请求的自然行为有冲突。

例如,在我的控制器中,我使用它:

$rootScope.ready()

此代码应该直接在$ rootScope脚本中迁移,该脚本跟踪视图的准备情况。

app.controller("WorksController", [

    "$scope", "cfpLoadingBar",

    function ($scope, cfpLoadingBar) {
        cfpLoadingBar.start();
        $scope.imgLoadedEvents = {
            always: function () {
                cfpLoadingBar.complete();
            }
        };
    }
]);

虽然,角度进度条仍然在后台运行。我让激活XHR拦截器。但是,如果在加载图像之前完成XHR请求,则即使视图尚未完成,进度条也会消失。同样,如果在XHR请求完成之前加载了图像,则进度条会消失。

如何将角度加载条的XHR拦截功能与此视图准备拦截功能集成?

4 个答案:

答案 0 :(得分:1)

在不修改angular-loaded-bar代码的情况下,这是不可能的,因为$ http拦截器没有你可以挂钩的任何API。

您应该在Github上分叉项目并修改cfb.loadingBarInterceptor。基本上你需要做的就是删除隐藏的代码并显示加载栏。将代码留在$rootScope上的广播事件中。这就是你要加入的内容。

  return {
    'request': function(config) {
      // Check to make sure this request hasn't already been cached and that
      // the requester didn't explicitly ask us to ignore this request:
      if (!config.ignoreLoadingBar && !isCached(config)) {
        $rootScope.$broadcast('cfpLoadingBar:loading', {url: config.url});            
      }
      return config;
    },

    'response': function(response) {
      if (!response || !response.config) {
        $log.error('Broken interceptor detected: Config object not supplied in response:\n https://github.com/chieffancypants/angular-loading-bar/pull/50');
        return response;
      }

      if (!response.config.ignoreLoadingBar && !isCached(response.config)) {
        $rootScope.$broadcast('cfpLoadingBar:loaded', {url: response.config.url, result: response});
      }
      return response;
    },

    'responseError': function(rejection) {
      if (!rejection || !rejection.config) {
        $log.error('Broken interceptor detected: Config object not supplied in rejection:\n https://github.com/chieffancypants/angular-loading-bar/pull/50');
        return $q.reject(rejection);
      }

      if (!rejection.config.ignoreLoadingBar && !isCached(rejection.config)) {
        $rootScope.$broadcast('cfpLoadingBar:loaded', {url: rejection.config.url, result: rejection});
      }
      return $q.reject(rejection);
    }
  };

现在,在您的运行块中,只需在底部添加这些行:

app.run(['$rootScope', function($rootScope){
  // Previous code ...

  $rootScope.$on("cfbLoadingBar:loaded", $rootScope.ready);
  $rootScope.$on("cfbLoadingBar:loading", $rootScope.loading);

});

如果不清楚这是做什么的,它会使用新的$ http拦截器中的事件,这会导致调用readyloading的方式与控制器的调用方式相同

答案 1 :(得分:1)

您所指的博客帖子是遗产

Google 将索引您的单页应用,不含任何html快照。

如果要创建快照(例如,使用尚不支持的规范标记!),则不应手动执行此操作,而应在构建过程中集成任务。使用Grunt / Gulp,这非常简单,可以在10分钟内完成。无需指定“就绪”事件 - phantomjs将识别脚本何时完成。

正确的方法是移动在状态下加载图像的功能解析功能。然后你不必担心将准备好的事件发送给幻像。 ;-)使用加载栏:

  $rootScope.$on('$stateChangeStart', function () {
            ngProgress.start();

              // or your:  cfpLoadingBar.start();

        });
  $rootScope.$on('$stateChangeSuccess', function () {
        ngProgress.complete();

               // or your:  cfpLoadingBar.complete();

        });

答案 2 :(得分:1)

正如@ anid-monsur指定的那样,如果不修改加载条代码就不可能做到。虽然,我想保留角度加载条的初始功能,所以我遵循他建议的不同路径。

我没有删除隐藏显示代码,而是在angular-loading-bar拦截器中添加了类似这样的自定义事件处理程序:

$rootScope.$on("cfpLoadingBar:customRequest", function(event, args){
    if (!args) {
      args = {};
    }
    if (!args.url){
      args.url = 'custom';
    }
    loading(args);
  });

  $rootScope.$on("cfpLoadingBar:customResponse", function(event, args){
    if (!args) {
      args = {};
    }
    if (!args.config){
      args.config = {};
    }
    if (!args.config.url){
      args.config.url = 'custom';
    }
    response(args);
  }); 

检查代码here

所以,当我的ui-router改变状态时,我可以写:

app.run(['$rootScope', 'cfpLoadingBar', function($rootScope, cfpLoadingBar){

    $rootScope.$broadcast("cfpLoadingBar:customRequest");

    $rootScope.ready = function(){
        $rootScope.$broadcast("cfpLoadingBar:customResponse");
    };

    $rootScope.loading = function(){
        $rootScope.$broadcast("cfpLoadingBar:customRequest");
    };

    $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
        $rootScope.$broadcast("cfpLoadingBar:customRequest");
    });

    $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams) {
        $rootScope.$broadcast("cfpLoadingBar:customResponse");
    });

}]);

注意添加的$ rootScope.ready()和$ rootScope.loading()

当控制器具有延迟加载过程时使用它们

例如,使用angular-imagesloaded:

app.controller("WorksController", [
    "$scope", '$rootScope',

    function ($scope, $rootScope) {

        $rootScope.loading();

        $scope.imgLoadedEvents = {
            done: function () {
                $rootScope.ready();
            }
        };

    }
]);

这样,我仍然可以使用angular-load-bar提供的本机拦截器并注册我自己的&#34; custom&#34;要求。

答案 3 :(得分:0)

这个问题与插件有关,因为 Anid Monsur 说。您可以解决仅将angular-loading-bar升级到最新版本或至少 7.0.1 + 的问题。