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高级程序设计 阅读笔记(十二) js内置对象Math
Aug 14 Javascript
js鼠标滑过弹出层的定位IE6bug解决办法
Dec 26 Javascript
js 弹出框只弹一次(二次修改之后的)
Nov 26 Javascript
javascript实现漂亮的拖动层,窗口拖拽特效
Apr 24 Javascript
ECMAScript6块级作用域及新变量声明(let)
Jun 12 Javascript
jquery实现表单验证简单实例演示
Nov 23 Javascript
jquery对Json的各种遍历方法总结(必看篇)
Sep 29 Javascript
jQuery实现对象转为url参数的方法
Jan 11 Javascript
js浏览器滚动条卷去的高度scrolltop(实例讲解)
Jul 07 Javascript
使用store来优化React组件的方法
Oct 23 Javascript
Vue使用鼠标在Canvas上绘制矩形
Dec 24 Vue.js
原生js中运算符及流程控制示例详解
Jan 05 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
PHP 多维数组排序实现代码
2009/08/05 PHP
PHP 各种排序算法实现代码
2009/08/20 PHP
php _autoload自动加载类与机制分析
2012/02/10 PHP
php实现单链表的实例代码
2013/03/22 PHP
php中通过curl检测页面是否被百度收录
2013/09/27 PHP
php数组中包含中文的排序方法
2014/06/03 PHP
php+xml编程之xpath的应用实例
2015/01/24 PHP
详解thinkphp实现excel数据的导入导出(附完整案例)
2016/12/29 PHP
PHP实现的支付宝支付功能示例
2019/03/26 PHP
tp5框架使用cookie加密算法实现登录功能示例
2020/02/10 PHP
YII2框架中ActiveDataProvider与GridView的配合使用操作示例
2020/03/18 PHP
javascript 面向对象编程 万物皆对象
2009/09/17 Javascript
元素未显示设置width/height时IE中使用currentStyle获取为auto
2014/05/04 Javascript
原生JavaScript编写canvas版的连连看游戏
2016/05/29 Javascript
React实现双向绑定示例代码
2016/09/19 Javascript
javascript 产生随机数的几种方法总结
2017/09/26 Javascript
zTree树形菜单交互选项卡效果的实现方法
2017/12/25 Javascript
jQuery幻灯片插件owlcarousel参数说明中文文档
2018/02/27 jQuery
Vue多系统切换实现方案
2018/06/05 Javascript
JavaScript键盘事件常见用法实例分析
2019/01/03 Javascript
简述ES6新增关键字let与var的区别
2019/08/23 Javascript
Typescript的三种运行方式(小结)
2019/09/18 Javascript
Angular8 实现table表格表头固定效果
2020/01/03 Javascript
JS+CSS实现3D切割轮播图
2020/03/21 Javascript
跟老齐学Python之变量和参数
2014/10/10 Python
详解Python with/as使用说明
2018/12/13 Python
Python函数生成器原理及使用详解
2020/03/12 Python
利用 Canvas实现绘画一个未闭合的带进度条的圆环
2019/07/26 HTML / CSS
Harrods英国:世界领先的奢侈品百货商店
2020/09/23 全球购物
2014世界杯球队球队口号
2014/06/05 职场文书
文明寝室标语
2014/06/13 职场文书
镇创先争优活动总结
2014/08/28 职场文书
研究生导师推荐信
2014/09/06 职场文书
运动员入场前导词
2015/07/20 职场文书
高一语文教学反思
2016/02/16 职场文书
SQL Server实现分页方法介绍
2022/03/16 SQL Server