【问题标题】:How to wait for resources to be loaded如何等待资源加载
【发布时间】:2015-03-31 06:43:21
【问题描述】:

我正在编写一个 AngularJS 应用程序,我正在尝试实现某些目标,但由于我对 Angular 很陌生,我想听听一些 AngularJS 专家的意见。

我实际上是在 AngularJS 中创建一个控制套件,它由两部分组成,加载屏幕和显示屏幕,均在 HTML 中定义。

我需要操作的数据存储在 JSON 文件中。 为了给你一个想法,这是第一个 JSon 文件:

{
  "Styles": [
    { "name": "Blue", "stylesheet": "/Resources/Stylesheets/Styles/Blue/OfficeUI.Style.Blue.min.css" },
    { "name": "Green", "stylesheet": "/Resources/Stylesheets/Styles/Green/OfficeUI.Style.Green.min.css" },
    { "name": "LightBlue", "stylesheet": "/Resources/Stylesheets/Styles/LightBlue/OfficeUI.Style.LightBlue.min.css" },
    { "name": "Orange", "stylesheet": "/Resources/Stylesheets/Styles/Orange/OfficeUI.Style.Orange.min.css" },
    { "name": "Purple", "stylesheet": "/Resources/Stylesheets/Styles/Purple/OfficeUI.Style.Purple.min.css" },
    { "name": "Red", "stylesheet": "/Resources/Stylesheets/Styles/Red/OfficeUI.Style.Red.min.css" },
    { "name": "Turquoise", "stylesheet": "/Resources/Stylesheets/Styles/Turquoise/OfficeUI.Style.Turquoise.min.css" }
  ],
  "DefaultStyle": "LightBlue",

  "Themes": [
    { "name": "No Background", "stylesheet": "/Resources/Stylesheets/Themes/No Background/OfficeUI.Themes.No-Background.min.css" },
    { "name": "Calligraphy", "stylesheet": "/Resources/Stylesheets/Themes/Calligraphy/OfficeUI.Themes.Calligraphy.min.css" },
    { "name": "Circles And Stripes", "stylesheet": "/Resources/Stylesheets/Themes/Circles-And-Stripes/OfficeUI.Themes.Circles-And-Stripes.min.css" },
    { "name": "Circuit", "stylesheet": "/Resources/Stylesheets/Themes/Circuit/OfficeUI.Themes.Circuit.min.css" },
    { "name": "Clouds", "stylesheet": "/Resources/Stylesheets/Themes/Clouds/OfficeUI.Themes.Clouds.min.css" },
    { "name": "Doodle Circles", "stylesheet": "/Resources/Stylesheets/Themes/Doodle-Circles/OfficeUI.Themes.Doodle-Circles.min.css" },
    { "name": "Doodle Diamonds", "stylesheet": "/Resources/Stylesheets/Themes/Doodle-Diamonds/OfficeUI.Themes.Doodle-Diamonds.min.css" },
    { "name": "Geometry", "stylesheet": "/Resources/Stylesheets/Themes/Geometry/OfficeUI.Themes.Geometry.min.css" },
    { "name": "Lunchbox", "stylesheet": "/Resources/Stylesheets/Themes/Lunchbox/OfficeUI.Themes.Lunchbox.min.css" },
    { "name": "School Supplies", "stylesheet": "/Resources/Stylesheets/Themes/School-Supplies/OfficeUI.Themes.School-Supplies.min.css" },
    { "name": "Spring", "stylesheet": "/Resources/Stylesheets/Themes/Spring/OfficeUI.Themes.Spring.min.css" },
    { "name": "Stars", "stylesheet": "/Resources/Stylesheets/Themes/Stars/OfficeUI.Themes.Stars.min.css" },
    { "name": "Straws", "stylesheet": "/Resources/Stylesheets/Themes/Straws/OfficeUI.Themes.Straws.min.css" },
    { "name": "Tree Rings", "stylesheet": "/Resources/Stylesheets/Themes/Tree-Rings/OfficeUI.Themes.Tree-Rings.min.css" },
    { "name": "Underwater", "stylesheet": "/Resources/Stylesheets/Themes/Underwater/OfficeUI.Themes.Underwater.min.css" }
  ],
  "DefaultTheme": "Geometry",
  "Configuration": "/Resources/Data/Application.json",
  "Controls": [
    { "Name": "Ribbon", "ConfigurationFile": "/Configuration/Application/OfficeUI.Ribbon.config.json" }
  ]
}

如您所见,该文件确实包含一些对样式表的引用,这些引用需要嵌入到页面动态中。

现在,让我们转到 AngularJS 部分。

首先,我有我的模块的定义:

var OfficeUI = angular.module('OfficeUIApplication', ['ngSanitize']);

然后,我确实有一个服务可以加载上面定义的 JSon 文件:

OfficeUI.factory('OfficeUIConfigurationService', function($http) {
    // Defines the object that this service needs to return.
    return {
        getOfficeUIConfiguration: function() {
            // Check if the location of the file can be found somewhere. If it cannot be found, throw an error.
            if (typeof $.fn.OfficeUI.Settings.OfficeUIConfigurationFileLocation === 'undefined' || $.fn.OfficeUI.Settings.OfficeUIConfigurationFileLocation == '') {
                OfficeUICore.Exceptions.officeUIConfigurationException('The OfficeUI Configuration file is not defined.');
            }

            // Returns the 'httpPromise' which is required for further processing.
            return $http.get($.fn.OfficeUI.Settings.OfficeUIConfigurationFileLocation)
                .then(function (response) {
                    return {
                        Styles: response.data.Styles,
                        DefaultStyle: response.data.DefaultStyle,
                        Themes: response.data.Themes,
                        DefaultTheme: response.data.DefaultTheme,
                        Configuration: response.data.Configuration,
                        Controls: response.data.Controls
                    };
                }, function(error) { OfficeUICore.Exceptions.officeUILoadingException('The OfficeUI Configuration file: \'' + $.fn.OfficeUI.Settings.OfficeUIConfigurationFileLocation + '\' could not be loaded.'); }
            );
        }
    }
});

然后,我有我的控制器:

OfficeUI.controller('OfficeUIController', function(OfficeUIConfigurationService, $scope, $http) {
    $scope.isInitialized = false;           // Indicates that the entire OfficeUI application has been loaded.
    $scope.loadingScreenLoaded = false;     // Indicates that the data for the loading screen has been loaded.

    // Initialize all the required components for the website.
    Initialize();

    function Initialize() {
        OfficeUIConfigurationService.getOfficeUIConfiguration().then(function(data) {
            var foundStyles = JSPath.apply('.{.name == "' + data.DefaultStyle + '"}', data.Styles);
            var foundThemes = JSPath.apply('.{.name == "' + data.DefaultTheme + '"}', data.Themes);

            $scope.Style = foundStyles[0].stylesheet;
            $scope.Theme = foundThemes[0].stylesheet;

            // Set a value that indicates that the loading screen has been loaded. So, at this point, the loading screen
            // can be rendered.
            $scope.loadingScreenLoaded = true;

            // Returns the 'httpPromise' which is required for further processing.
            $http.get(data.Configuration)
                .then(function (response) {
                        $scope.Title = response.data.Title;
                        $scope.Icons = response.data.Icons;
                }, function(error) { OfficeUICore.Exceptions.officeUILoadingException('The OfficeUI application definition file: \'' + data.Configuration + '\' could not be loaded.'); }
            );
        });

        setTimeout(function() {
            $scope.isInitialized = true;
            $scope.$apply();
        }, 2000);
    }
});

注意:我确实在此处设置了超时,以确保加载屏幕显示 2 秒。

在这个控制器中,您可以找到以下代码:

OfficeUIConfigurationService.getOfficeUIConfiguration().then(function(data) {
    var foundStyles = JSPath.apply('.{.name == "' + data.DefaultStyle + '"}', data.Styles);
    var foundThemes = JSPath.apply('.{.name == "' + data.DefaultTheme + '"}', data.Themes);
    $scope.Style = foundStyles[0].stylesheet;
    $scope.Theme = foundThemes[0].stylesheet;
    // Set a value that indicates that the loading screen has been loaded. So, at this point, the loading screen
    // can be rendered.
    $scope.loadingScreenLoaded = true;
    // Returns the 'httpPromise' which is required for further processing.
    $http.get(data.Configuration)
        .then(function (response) {
                $scope.Title = response.data.Title;
                $scope.Icons = response.data.Icons;
        }, function(error) { OfficeUICore.Exceptions.officeUILoadingException('The OfficeUI application definition file: \'' + data.Configuration + '\' could not be loaded.'); }
    );
});

这样做的目的是,从我的加载服务中检索并解析 JSon 文件,并根据该文件中的值,为 StyleTheme 分配一个值,它们都是范围对象。

在我的 HTML 中,这是这样呈现的(在文件的头部):

<link rel="stylesheet" href="#" data-ng-href="{{Style}}" />
<link rel="stylesheet" href="#" data-ng-href="{{Theme}}" />

这使我可以动态更改应用程序的外观和感觉(通过调用更改范围值的方法)。

但是,可能会出现闪烁问题。当 Json 文件被加载和解析时,我为 loadingScreenLoaded 分配一个值,以确保正在显示加载屏幕:

<div class="loading-area center-screen no-select" data-ng-if="loadingScreenLoaded && !isInitialized">

但是,在这种特殊情况下,CSS 文件可能仍在加载中。

所以问题是,如何在页面上不显示加载 div,直到所有资源都已加载(CSS,...)

另外,如果可能的话,有没有办法对 ng-include 指令、图像、...做同样的事情。

亲切的问候,

【问题讨论】:

    标签: javascript jquery css json angularjs


    【解决方案1】:

    不建议使用超时,我不能指望你的资源会在2000年之后准备好

    setTimeout(function() {
            $scope.isInitialized = true;
            $scope.$apply();
        }, 2000);
    

    我会推荐你​​使用文件和模块加载器库。尝试使用 angular 和 requirejs

    查看这个使用angularjs + requirejs的例子

    【讨论】:

    • 问题上有一个注释说现在,它只是为了确保加载屏幕显示2秒(否则它几乎会立即消失)。而且我看不出 requireJS 在这种情况下如何帮助我。问题是如何等到资源准备好,A.K.A.预加载。
    【解决方案2】:

    标签有事件“onload”。详情here。但是,如果它满足您需要的所有浏览器,您应该检查浏览器兼容性。

    <link rel="stylesheet" href="mystylesheet.css" onload="sheetLoaded()" onerror="sheetError()">
    

    在其他情况下,您可以考虑动态资源加载技术。例如this。此外,您可以使用实际实现动态资源加载的第三方库(angular-load 或者,正如@ran 所说,requirejs)。

    问题是如何等到资源准备好

    您可以将事件处理程序附加到“onload”(或第三方库特定事件,这取决于您的选择),这将在您的资源准备好时执行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 1970-01-01
      • 1970-01-01
      • 2018-11-08
      • 2021-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多