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 相关文章推荐
PJ Blog修改-禁止复制的代码和方法
Oct 25 Javascript
跨域表单提交状态的变相判断代码
Nov 12 Javascript
javascript 获取模态窗口的滚动位置代码
Aug 06 Javascript
使用jquery解析XML的方法
Sep 05 Javascript
原生JS和JQuery动态添加、删除表格行的方法
May 28 Javascript
学习JavaScript设计模式之享元模式
Jan 18 Javascript
详解Node.js模块间共享数据库连接的方法
May 24 Javascript
js学习笔记之事件处理模型
Oct 31 Javascript
详解node HTTP请求客户端 - Request
May 05 Javascript
javascript数据结构之多叉树经典操作示例【创建、添加、遍历、移除等】
Aug 01 Javascript
Vue 进阶之路(三)
Apr 18 Javascript
vue路由结构可设一层方便动态添加路由操作
Aug 31 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+MySql编写聊天室
2006/10/09 PHP
PHP 下载文件时自动添加bom头的方法实例
2014/01/10 PHP
求帮忙修改个php curl模拟post请求内容后并下载文件的解决思路
2015/09/20 PHP
php实用代码片段整理
2016/11/12 PHP
IE 下的只读 innerHTML
2009/08/21 Javascript
JavaScript函数模式详解
2014/11/07 Javascript
js实现两点之间画线的方法
2015/05/12 Javascript
jquery操作angularjs对象
2015/06/26 Javascript
Bootstrap3 input输入框插入glyphicon图标的方法
2016/05/16 Javascript
jquery+ajax实现直接提交表单实例分析
2016/06/17 Javascript
微信小程序之页面跳转和参数传递的实现
2017/09/29 Javascript
jQuery实现表单动态添加数据并提交的方法
2018/07/19 jQuery
Vue 组件封装 并使用 NPM 发布的教程
2018/09/30 Javascript
jQuery选择器之基本选择器用法实例分析
2019/02/19 jQuery
[31:33]2014 DOTA2国际邀请赛中国区预选赛 TongFu VS DT 第一场
2014/05/23 DOTA
[06:23]2014DOTA2西雅图国际邀请赛 小组赛7月12日TOPPLAY
2014/07/12 DOTA
Python中实现单例模式的n种方式和原理
2018/11/14 Python
python游戏地图最短路径求解
2019/01/16 Python
Python3.5多进程原理与用法实例分析
2019/04/05 Python
python对文件的操作方法汇总
2020/02/28 Python
基于Python爬取fofa网页端数据过程解析
2020/07/13 Python
详解pandas中利用DataFrame对象的.loc[]、.iloc[]方法抽取数据
2020/12/13 Python
美国渔具店:FishUSA
2019/08/07 全球购物
请解释一下webService? 如何用.net实现webService
2014/06/09 面试题
总经理岗位职责范本
2014/02/02 职场文书
土木工程专业推荐信
2014/02/19 职场文书
法律进机关实施方案
2014/03/12 职场文书
大学生实习证明范文(5篇)
2014/09/18 职场文书
学习党的群众路线教育实践活动剖析材料
2014/10/13 职场文书
捐款感谢信
2015/01/20 职场文书
陕西导游词
2015/02/04 职场文书
患者身份识别制度
2015/08/06 职场文书
2016年元旦寄语
2015/08/17 职场文书
2016年优秀班主任先进事迹材料
2016/02/26 职场文书
基于tensorflow权重文件的解读
2021/05/26 Python
html中显示特殊符号(附带特殊字符对应表)
2021/06/21 HTML / CSS