【问题标题】:AngularJS: How to prevent "code flash" in page while loadingAngularJS:如何在加载时防止页面中的“代码闪烁”
【发布时间】:2015-04-15 08:37:17
【问题描述】:

我使用 AngularJS 创建了一个简单的应用程序。当我打开页面一秒钟时,我看到下面的屏幕:

但是,加载完成后,我看到加载和样式化的内容很好:

如何防止 AngularJS 代码在我的页面上闪烁?这和FOUC有关吗?

这是 HTML 代码:

<!doctype html>
<html class="no-js" lang="en" ng-app="MainApp">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Foundation | Welcome</title>
    <link rel="stylesheet" href="css/foundation.css" />
    <script src="js/vendor/modernizr.js"></script>

    <style>
    .row.full-width {
        width: 100%;
        margin-left: auto;
        margin-right: auto;
        max-width: initial;
    }
    </style>

</head>

<body ng-controller="MainCtrl">
    <div class="off-canvas-wrap" data-offcanvas>
        <div class="inner-wrap">
            <nav class="tab-bar">
                <section class="right-small">
                    <a class="right-off-canvas-toggle menu-icon" href="#"><span></span></a>
                </section>
                <section class="left tab-bar-section">
                    <h1 class="title">Salary Calculator</h1>
                </section>
            </nav>

            <aside class="right-off-canvas-menu">
                <ul class="off-canvas-list">
                    <li>
                        <label>Location</label>
                    </li>
                    <li><a href="#">United Kingdom</a>
                    </li>
                </ul>
            </aside>

            <section class="main-section">


                <div class="row full-width">
                    <div class="large-4 columns">

                        <ul class="tabs" data-tab>
                            <li class="tab-title active"><a href="#panel1">Annual Salary</a>
                            </li>
                            <li class="tab-title"><a href="#panel2">Monthly Expenses</a>
                            </li>
                        </ul>
                        <div class="tabs-content">
                            <div class="content active" id="panel1">
                                <div class="row">
                                    <div class="large-12 columns">
                                        <input ng-change="calculate()" type="text" placeholder="Salary" ng-model="salary"/>
                                    </div>
                                </div>
                            </div>
                            <div class="content" id="panel2">
                                <div class="row">
                                    <div class="large-4 columns">
                                        <input ng-change="calculate()" type="text" placeholder="Rent" ng-model="rent" />
                                    </div>
                                    <div class="large-4 columns">
                                        <input ng-change="calculate()" type="text" placeholder="Wireless, TV, Home Phone" ng-model="telecom"/>
                                    </div>

                                    <div class="large-4 columns">
                                        <input ng-change="calculate()" type="text" placeholder="TV License" ng-model="tv" />
                                    </div>
                                </div>

                                <div class="row">
                                    <div class="large-4 columns">
                                        <input ng-change="calculate()" type="text" placeholder="Mobile Phone" ng-model="mobile"/>
                                    </div>
                                    <div class="large-4 columns">
                                        <input ng-change="calculate()" type="text" placeholder="Subscription" ng-model="subscription"/>
                                    </div>

                                    <div class="large-4 columns">
                                        <input ng-change="calculate()" type="text" placeholder="Electricty" ng-model="electricity" />
                                    </div>
                                </div>

                                <div class="row">
                                    <div class="large-4 columns">
                                        <input ng-change="calculate()" type="text" placeholder="Food" ng-model="food"/>
                                    </div>
                                    <div class="large-4 columns">
                                        <input ng-change="calculate()" type="text" placeholder="Transport" ng-model="transport" />
                                    </div>

                                    <div class="large-4 columns">
                                        <input ng-change="calculate()" type="text" placeholder="Charity" ng-model="charity"/>
                                    </div>
                                </div>

                                <div class="row">
                                    <div class="large-12 columns">
                                        <input ng-change="calculate()" type="text" placeholder="Other" ng-model="other"/>
                                    </div>
                                </div>

                            </div>
                        </div>

                    </div>
                    <div class="large-8 columns"  ng-cloak >
                        <table >
                       <thead>
                            <tr>
                                <th width="200"></th>
                                <th width="250">Yearly</th>
                                <th width="250">Monthly</th>
                                <th width="250">Weekly</th>
                                <th width="250">Daily</th>
                            </tr>
                        </thead>
                        <tbody ng-repeat="val in results">
                            <tr>
                                <td>{{val.rowType}}</td>
                                <td>{{val.yearly}}</td>
                                <td>{{val.monthly}}</td>
                                <td>{{val.weekly}}</td>
                                <td>{{val.daily}}</td>

                            </tr>
                        </tbody>
                        </table>

                    </div>
                </div>



            </section>

            <a class="exit-off-canvas"></a>

        </div>
    </div>

    <script src="../bower_components/angularjs/angular.js"></script>


    <script src="js/app-service.js"></script>
    <script src="js/app-controller.js"></script>
    <script src="js/app-directives.js"></script>
    <script src="js/app.js"></script>

    <script src="js/vendor/jquery.js"></script>
    <script src="js/foundation.min.js"></script>

    <script>
    $(document).foundation();
    </script>
</body>

</html>

编辑:

请参阅my answer 以获取除了已接受的解决方案之外的替代解决方案。

【问题讨论】:

标签: javascript angularjs zurb-foundation fouc


【解决方案1】:

Angular 已经为您提供了防止这种情况发生的工具:ngCloak:https://docs.angularjs.org/api/ng/directive/ngCloak

只需像&lt;body ng-cloak&gt; 一样将指令放在你的身体上,它应该可以工作。

编辑 文档还建议您实际上不要将其放在正文上,而应放在页面的较小部分 - 无论您认为需要什么。根据页面的大小,这是一个好主意。对于较小的页面,我将它放在身体上,从来没有问题。

【讨论】:

  • 谢谢。这使过渡更快,但不幸的是并没有完全解决它。我仍然看到代码。
【解决方案2】:

ng-cloak 会在一定程度上有所帮助,但您可以使用 ng-bind 指令而不是使用 {{ }} 来完全阻止它。

例如

<td ng-bind="val.monthly"> </td>

不是

<td>{{val.monthly}}</td>

【讨论】:

  • 这还有另一个好处,即您可以提供一些默认文本,直到加载模板。例如。 &lt;h1 ng-bind="title"&gt;Loading...&lt;/h1&gt;
【解决方案3】:

除了ng-cloak,您还可以在路由器中使用resolve object。这将阻止控制器实例化和渲染视图,直到数据存在。

在以下示例中,我假设您使用的是uiRouter。同样的模式适用于ngRouter

你的状态配置:

$stateProvider
    .state('yourState',{
        templateUrl: 'yourTemplate.html',
        controller: 'YourController as vm',
        resolve: YourController.resolve
    })

如您所见,您已将状态的解析属性设置为控制器上的静态解析对象。现在,在此对象被解析之前,路由不会解析。

要设置解析对象,假设您有一个服务yourService,它有一个方法getData 返回一个承诺。这个非常重要。因为我们不希望在 promise 解决之前解决路由

所以你的控制器可能看起来像这样。

YourController.$inject = ['yourService'];
function YourController(yourService) {
    var self = this;
    yourService.getData().then((data) { self.data = data});
}

这是相当标准的。您可以使用vm.data 从视图中访问数据,但您会看到{{vm.data}} 的闪烁。也就是说,如果我们删除我们添加到状态配置中的解析。

所以现在我们更改控制器以添加一个静态解析对象,以使用我们添加到状态配置中的resolve

YourController.resolve = {
    'yourService': 'yourService',
    'data': ['yourService', function(yourService) {
        return yourService.getData();    
    }]
}

YourController.$inject = ['data'];
function YourController(data) {
    this.data = data;
}

所以现在我们有了一个解析对象。 yourService 将作为普通服务解析,但 data 属性仅在 getData() 返回的承诺被解析时才会解析。然后这个data 将使用依赖注入直接传递给控制器​​。

实际上,如果您使用resolve,您可能不需要使用ng-cloak

这是一个工作示例:

angular.module('app', ['ui.router'])

.config(['$stateProvider',
  function($stateProvider) {

    $stateProvider
    
      .state('noDot', {
        controller: "NoDotController",
        template: "Using a old style $scope binding {{customers[0].CutomerName}}"
      })
             
      .state('noResolve', {
        controller: "NoResolveController as vm",
        template: "We are displaying things before the data is here {{vm.customers[0].CustomerName}}"
      })

    .state('withResolve', {
      controller: "WithResolveController as vm",
      template: "We are waiting for data before displaying anything {{vm.customers[0].CustomerName}}",
      resolve: WithResolveController.resolve
    })

    .state('empty', {
      template: ""
    })

  }
])

.controller('NoResolveController', NoResolveController)
  .controller('NoDotController', NoDotController)
  .controller('WithResolveController', WithResolveController)
  .service('northwind', Northwind);

NoDotController.$inject = ['$scope', 'northwind'];
function NoDotController($scope, northwind) {
  northwind.getCustomers().then(function(customers) {
    $scope.customers = customers});
}

NoResolveController.$inject = ['northwind'];
function NoResolveController(northwind) {
  var self = this;
  northwind.getCustomers().then(function(customers) {
    self.customers = customers;
  });
}

WithResolveController.resolve = {
  'northwind': 'northwind',
  'customers': ['northwind',
    function(northwind) {
      return northwind.getCustomers();
    }
  ]
}
WithResolveController.$inject = ['customers'];
function WithResolveController(customers) {
  this.customers = customers;
}

Northwind.$inject = ['$timeout', '$q'];
function Northwind($timeout, $q) {
  this.$q = $q;
  this.$timeout = $timeout;
}
Northwind.prototype.getCustomers = function() {
  var deferred = this.$q.defer();

  this.$timeout(function() {
    deferred.resolve([{CustomerName: "Name of Customer"}])
  }, 1000);

  return deferred.promise;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.13/angular-ui-router.js"></script>
<div ng-app="app">
  <a ui-sref="noDot" href="#">No Dot</a>
  <span> | </span>
  <a ui-sref="empty" href="#">Emtpy</a>
  <span> | </span>
  <a ui-sref="noResolve" href="#">No Resolve</a>
  <span> | </span>
  <a ui-sref="empty" href="#">Emtpy</a>
  <span> | </span>
  <a ui-sref="withResolve" href="#">With Resolve</a>
  <br>
  <br>
  <ui-view></ui-view>

</div>

【讨论】:

    【解决方案4】:

    已经很久了,但这是我的工作解决方案:

    你需要在你的html的body标签上使用ng-cloak,但最重要的部分是下面的这个CSS:

    [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; }

    对我来说,我必须添加这个才能让 ng-cloak 工作。正如在其他答案中所见,这可能不是解决此问题的唯一方法。希望这对某人有所帮助。

    【讨论】:

    • 除了添加 CSS 样式外,我还需要将 ng-clock 指令添加到包含我的 ng-app 指令的元素中:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-24
    • 1970-01-01
    • 2017-06-21
    • 2020-10-05
    • 1970-01-01
    • 2021-11-19
    • 1970-01-01
    相关资源
    最近更新 更多