javascript AngularJS:如何在加载时防止页面中的“代码闪烁”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28514241/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AngularJS: How to prevent "code flash" in page while loading
提问by Cemre
I have created a simple app using AngularJS. When I open the page for a second I see the screen below:
我使用 AngularJS 创建了一个简单的应用程序。当我打开页面一秒钟时,我看到下面的屏幕:


However, after the load is complete I see the loaded and styled content which is fine:
但是,加载完成后,我看到加载和样式化的内容很好:


How do I prevent the flash of AngularJS code on my page ? Is this related to FOUC ?
如何防止 AngularJS 代码在我的页面上闪烁?这与FOUC有关吗?
Here is the HTML code:
这是 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>
EDIT:
编辑:
Please see my answeras well for an alternative solution in addition to the accepted one.
除了已接受的解决方案之外,请参阅我的回答以获取替代解决方案。
回答by mikel
ng-cloak will help to some extent, but you can fully prevent it using ng-bind directive instead of using {{ }}.
ng-cloak 会在一定程度上有所帮助,但您可以使用 ng-bind 指令而不是使用{{ }}.
e.g.
例如
<td ng-bind="val.monthly"> </td>
not
不是
<td>{{val.monthly}}</td>
回答by Cemre
It has been a long time but here is for my working solution for this one:
已经很长时间了,但这是我对此的工作解决方案:
You need to use ng-cloakon the body tag of your html BUT the most important part is this CSS below:
您需要ng-cloak在 html 的 body 标签上使用,但最重要的部分是下面的 CSS:
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
For me I had to add this for getting ng-cloak to work. This is probably not the only solution to this problem as can be seen in other answers. Hope this helps someone.
对我来说,我必须添加这个才能让 ng-cloak 工作。正如其他答案中所见,这可能不是此问题的唯一解决方案。希望这可以帮助某人。
回答by David Losert
Angular already gives you the tool to prevent this: ngCloak: https://docs.angularjs.org/api/ng/directive/ngCloak
Angular 已经为您提供了防止这种情况的工具ngCloak:https: //docs.angularjs.org/api/ng/directive/ngCloak
Just put the directive on your body like <body ng-cloak>and it should work.
只需将指令放在您的身体上<body ng-cloak>,它就应该起作用。
EDITThe Docs also advice you to actually not put it on the body, but on smaller portions of your page - wherever you see the need. Depending on the size of your page, that is a good idea. For smaller Pages I put it on the body and never had problems.
编辑文档还建议您实际上不要将其放在正文上,而是放在页面的较小部分 - 无论您需要什么。根据页面的大小,这是一个好主意。对于较小的页面,我把它放在身体上,从来没有问题。
回答by Martin
Along with ng-cloak, you can use a resolve objectin your router. This will prevent the controller from instantiating and the view from rendering until the data is there.
与 一起ng-cloak,您可以resolve object在路由器中使用 a 。这将阻止控制器实例化和视图渲染,直到数据存在。
In the following example I am assuming you are using uiRouter. The same pattern applies for ngRouter.
在以下示例中,我假设您使用的是uiRouter. 同样的模式适用于ngRouter.
Your state config:
您的状态配置:
$stateProvider
.state('yourState',{
templateUrl: 'yourTemplate.html',
controller: 'YourController as vm',
resolve: YourController.resolve
})
As you can see, you have set the resolve property of the state to a static resolve object on your controller. Now the route will not resolve until this object is resolved.
如您所见,您已将状态的解析属性设置为控制器上的静态解析对象。现在路由不会解析,直到这个对象被解析。
To setup resolve object, lets assume you have a service yourServicethat has a method getDatathat returns a promise. This is very important. Because we don't want the route resolved until the promise is resolved.
要设置解析对象,让我们假设您有一个yourService具有getData返回承诺的方法的服务。这是非常重要的。因为我们不希望在 promise 被解决之前路由被解决。
So your controller may look something like this.
所以你的控制器可能看起来像这样。
YourController.$inject = ['yourService'];
function YourController(yourService) {
var self = this;
yourService.getData().then((data) { self.data = data});
}
This is pretty standard. You can access the data from the view with vm.databut you will see a flash of {{vm.data}}. That is, if we remove the resolve we have added to the state config.
这是很标准的。您可以从视图中访问数据,vm.data但您会看到{{vm.data}}. 也就是说,如果我们删除添加到状态配置中的解析。
So now we change the controller to add a static resolve object to work with the resolvewe have added to the state config.
因此,现在我们更改控制器以添加一个静态解析对象以与resolve我们添加到状态配置中的对象一起使用。
YourController.resolve = {
'yourService': 'yourService',
'data': ['yourService', function(yourService) {
return yourService.getData();
}]
}
YourController.$inject = ['data'];
function YourController(data) {
this.data = data;
}
So now we have a resolve object. The yourServicewill resolve as a normal service, but the dataproperty will resolve only when the promise returned by getData()is resolved. Then this datawill be passed directly into the controller using Dependancy Injection.
所以现在我们有一个解析对象。在yourService将解决作为一个正常的服务,但该data属性将解决只有当返回的承诺getData()得到解决。然后这data将使用依赖注入直接传递到控制器中。
In reality, you probably wont need to use ng-cloakif you use resolve.
实际上,ng-cloak如果您使用resolve.
Here is a working example:
这是一个工作示例:
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>

