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-cloak
on 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 object
in 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 yourService
that has a method getData
that 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.data
but 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 resolve
we 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 yourService
will resolve as a normal service, but the data
property will resolve only when the promise returned by getData()
is resolved. Then this data
will be passed directly into the controller using Dependancy Injection.
所以现在我们有一个解析对象。在yourService
将解决作为一个正常的服务,但该data
属性将解决只有当返回的承诺getData()
得到解决。然后这data
将使用依赖注入直接传递到控制器中。
In reality, you probably wont need to use ng-cloak
if 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>