AngularJS页面访问时出现页面闪烁问题的解决


Posted in Javascript onMarch 06, 2016

我们知道在应用的页面或者组件需要加载数据时,浏览器和angular渲染页面都需要消耗一定的时间。这里的间隔可能很小,甚至让人感觉不到区别;但也可能很长,这样会导致让我们的用户看到了没有被渲染过的页面。

这种情况被叫做Flash Of Unrendered Content (FOUC)(K)?and is always unwanted.下面我们将要介绍几个不同的方式防止这种情况发生在我们的用户身上。

1、ng-cloak
ng-cloak指令是angular的内置指令,它的作用是隐藏所有被它包含的元素:

<div ng-cloak>
 <h1>Hello {{ name }}</h1>
</div>

Ng-cloak实现原理为一个directive,页面初始化是在DOM的heade增加一行CSS代码,如下:

<pre class= “prettyprint linenums”>

  [ng\:cloak],[ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak{

  Display:none ! important;

}

</pre>

<pre class= “prettyprint linenums”>
 
  [ng\:cloak],[ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak{
 
  Display:none ! important;
 
}
 
</pre>

Angular将带有ng-cloak的元素设置为display:none.

在等到angular解析到带有ng-cloak节点的时候,会把元素上ng-cloak  attribute和calss同时remove掉,这样就防止了节点的闪烁。如下:

<script type =”text/ng-template” id =”scenario.js-150”>

  It(‘should remove the template directive and css class',function(){

 Expect(element(‘.doc-example-live #template1').attr(‘ng-cloak'))

  not().toBeDefined();

   Expect(element(‘.doc-example-live #template2').attr(‘ng-cloak')).

Not().toBeDefined();

});

</script>

<script type =”text/ng-template” id =”scenario.js-150”>
 
  It(‘should remove the template directive and css class',function(){
 
 Expect(element(‘.doc-example-live #template1').attr(‘ng-cloak'))
 
  not().toBeDefined();
 
   Expect(element(‘.doc-example-live #template2').attr(‘ng-cloak')).
 
Not().toBeDefined();
 
});
 
</script>

2、ng-bind
ng-bind是angular里面另一个内置的用于操作绑定页面数据的指令。我们可以使用ng-bind代替{{ }}的形式绑定元素到页面上;

使用ng-bind替代{{  }}可以防止未被渲染的{{ }}就展示给用户了,使用ng-bind渲染的空元素替代{{ }}会显得友好很多。

上面的例子可以重写成下面那样,这样就可以防止页面出现{{ }}了

<div>
 <h1>Hello <span ng-bind="name"></span></h1>
</div>

3、resolve
当在不同的页面之间使用routes(路由)的时候,我们有另外的方式防止页面在数据被完全加载到route之前被渲染。

在route(路由)里使用resolve可以让我们在route(路由)被完全加载之前获取我们需要加载的数据。当数据被加载成功之后,路由就会改变而页面也会呈现给用户;数据没有被加载成功route就不会改变, the $routeChangeError event will get fired.【$routeChangeError事件就(不)会被激活?】

angular.module('myApp', ['ngRoute'])
.config(function($routeProvider) {
 $routeProvider
 .when('/account', {
 controller: 'AccountCtrl',
 templateUrl: 'views/account.html',
 resolve: {
  // We specify a promise to be resolved
  account: function($q) {
  var d = $q.defer();
  $timeout(function() {
   d.resolve({
   id: 1,
   name: 'Ari Lerner'
   })
  }, 1000);
  return d.promise;
  }
 }
 })
});

resolve 项需要一个key/value对象,key是resolve依赖的名称,value可以是一个字符串(as a service)或者一个返回依赖的方法。

resolve is very useful when the resolve value returns a promise that becomes resolved or rejected.

当路由加载的时候,resolve参数里的keys可以作为可注入的依赖:

angular.module('myApp')
.controller('AccountCtrl', 
 function($scope, account) {
 $scope.account = account;
});

我们同样可以使用resolve key传递$http方法返回的结果,as $http returns promises from it's method calls:

angular.module('myApp', ['ngRoute'])
.config(function($routeProvider) {
 $routeProvider
 .when('/account', {
 controller: 'AccountCtrl',
 templateUrl: 'views/account.html',
 resolve: {
  account: function($http) {
  return $http.get('http://example.com/account.json')
  }
 }
 })
});

推荐定义一个独立的service的方式来使用resolve key,并且使用service来相应返回所需的数据(这种方式更容易测试)。要这样处理的话,我们需要创建一个service:

首先,看一下accountService,

angular.module('app')
.factory('accountService', function($http, $q) {
 return {
 getAccount: function() {
  var d = $q.defer();
  $http.get('/account')
  .then(function(response) {
  d.resolve(response.data)
  }, function err(reason) {
  d.reject(reason);
  });
  return d.promise;
 }
 }
})

定义好service之后我们就可以使用这个service来替换上面代码中直接调用$http的方式了:

angular.module('myApp', ['ngRoute'])
.config(function($routeProvider) {
 $routeProvider
 .when('/account', {
 controller: 'AccountCtrl',
 templateUrl: 'views/account.html',
 resolve: {
  // We specify a promise to be resolved
  account: function(accountService) {
  return accountService.getAccount()
  }
 }
 })
});
Javascript 相关文章推荐
javascript instanceof 与typeof使用说明
Jan 11 Javascript
jQuery产品间断向下滚动效果核心代码
May 08 Javascript
jQuery遍历页面所有CheckBox查看是否被选中的方法
Apr 14 Javascript
学习使用jquery iScroll.js移动端滚动条插件
Mar 24 Javascript
原生JS实现左右箭头选择日期实例代码
Mar 14 Javascript
Angular之toDoList的实现代码示例
Dec 02 Javascript
vue实现点击当前标签高亮效果【推荐】
Jun 22 Javascript
基于axios 解决跨域cookie丢失的问题
Sep 26 Javascript
JS数组中对象去重操作示例
Jun 04 Javascript
手写Vue弹窗Modal的实现代码
Sep 11 Javascript
vue实现百度语音合成的实例讲解
Oct 14 Javascript
js通过canvas生成图片缩略图
Oct 02 Javascript
JavaScript模拟数组合并concat
Mar 06 #Javascript
JavaScript模拟push
Mar 06 #Javascript
JavaScript中利用jQuery绑定事件的几种方式小结
Mar 06 #Javascript
Node.js模块封装及使用方法
Mar 06 #Javascript
JavaScript中三种异步上传文件方式
Mar 06 #Javascript
JavaScript中获取纯正的undefined的方法
Mar 06 #Javascript
JS面向对象编程详解
Mar 06 #Javascript
You might like
为了这两部电子管收音机,买了6套全新电子管和10粒刻度盘灯泡
2021/03/02 无线电
单一index.php实现PHP任意层级文件夹遍历(Zjmainstay原创)
2012/07/31 PHP
php中jpgraph类库的使用介绍
2013/08/08 PHP
搭建基于Docker的PHP开发环境的详细教程
2015/07/01 PHP
PHP实现数组array转换成xml的方法
2016/07/19 PHP
浅谈PHP安全防护之Web攻击
2017/01/03 PHP
JSON语法五大要素图文介绍
2012/12/04 Javascript
HTML复选框和单选框 checkbox和radio事件介绍
2012/12/12 Javascript
js 将json字符串转换为json对象的方法解析
2013/11/13 Javascript
jquery实现简单的二级导航下拉菜单效果
2015/09/07 Javascript
AngularJS实现分页显示数据库信息
2016/07/01 Javascript
全屏滚动插件fullPage.js使用实例解析
2016/10/21 Javascript
jQuery之动画ajax事件(实例讲解)
2017/07/18 jQuery
JavaScript调试之console.log调试的一个小技巧分享
2017/08/07 Javascript
基于DOM节点删除之empty和remove的区别(详解)
2017/09/11 Javascript
Nodejs连接mysql并实现增、删、改、查操作的方法详解
2018/01/04 NodeJs
angularjs $http调用接口的方式详解
2018/08/13 Javascript
layui自定义ajax左侧三级菜单
2019/07/26 Javascript
JS实现点击下拉列表文本框中出现对应的网址,点击跳转按钮实现跳转
2019/11/25 Javascript
高性能js数组去重(12种方法,史上最全)
2019/12/21 Javascript
[51:53]完美世界DOTA2联赛循环赛 LBZS vs DM BO2第二场 11.01
2020/11/02 DOTA
利用python和百度地图API实现数据地图标注的方法
2019/05/13 Python
python3.6中@property装饰器的使用方法示例
2019/08/17 Python
Python生成验证码、计算具体日期是一年中的第几天实例代码详解
2019/10/16 Python
Python selenium模块实现定位过程解析
2020/07/09 Python
Html5新增标签有哪些
2017/04/13 HTML / CSS
机电专业大学生求职信
2013/10/04 职场文书
给朋友的道歉信
2014/01/09 职场文书
公司离职证明范本
2014/01/13 职场文书
建材投资建议书
2014/05/16 职场文书
就职演讲稿范文
2014/05/19 职场文书
车间安全生产标语
2014/06/06 职场文书
匿名检举信范文
2015/03/02 职场文书
政协委员个人总结
2015/03/03 职场文书
爱鸟护鸟的宣传语
2015/07/13 职场文书
法制工作总结2015
2015/07/23 职场文书