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 相关文章推荐
jQuery之选择组件的深入解析
Jun 19 Javascript
js实现的全国省市二级联动下拉选择菜单完整实例
Aug 17 Javascript
EasyUi combotree 实现动态加载树节点
Apr 01 Javascript
javascript css红色经典选项卡效果实现代码
May 17 Javascript
jQuery实现输入框邮箱内容自动补全与上下翻动显示效果【附demo源码下载】
Sep 20 Javascript
Angular4 中常用的指令入门总结
Jun 12 Javascript
以BootStrap Tab为例写一个前端组件
Jul 25 Javascript
JS库particles.js创建超炫背景粒子插件(附源码下载)
Sep 13 Javascript
浅谈Vue-cli 命令行工具分析
Nov 22 Javascript
基于Bootstrap下拉框插件bootstrap-select使用方法详解
Aug 07 Javascript
ES6模板字符串和标签模板的应用实例分析
Jun 25 Javascript
如何实现echarts markline标签名显示自己想要的
Jul 20 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/03/10 PHP
PHP5中使用DOM控制XML实现代码
2010/05/07 PHP
php for 循环语句使用方法详细说明
2010/05/09 PHP
PHP,ASP.JAVA,JAVA代码格式化工具整理
2010/06/15 PHP
php的慢速日志引起的Mysql错误问题分析
2014/05/13 PHP
php数组添加与删除单元的常用函数实例分析
2015/02/16 PHP
PHP中Restful api 错误提示返回值实现思路
2016/04/12 PHP
PHP使用openssl扩展实现加解密方法示例
2020/02/20 PHP
Javascript学习笔记二 之 变量
2010/12/15 Javascript
浅析Javascript ES6中的原生Promise
2016/08/25 Javascript
jQuery常用样式操作实例分析(获取、设置、追加、删除、判断等)
2016/09/08 Javascript
javascript使用闭包模拟对象的私有属性和方法
2016/10/05 Javascript
使用vue构建移动应用实战代码
2017/08/02 Javascript
关于meta viewport中target-densitydpi属性详解(推荐)
2017/08/18 Javascript
解决Vue动态加载本地图片问题
2019/10/09 Javascript
JavaScript 引用类型实例详解【数组、对象、严格模式等】
2020/05/13 Javascript
Python中的面向对象编程详解(下)
2015/04/13 Python
python 读写txt文件 json文件的实现方法
2016/10/22 Python
详解Python中的type和object
2018/08/15 Python
处理Selenium3+python3定位鼠标悬停才显示的元素
2019/07/31 Python
python 基于selectors库实现文件上传与下载
2020/12/31 Python
伦敦剧院及景点门票:Encore Tickets
2018/07/01 全球购物
捷克厨房用品购物网站:Tescoma
2018/07/13 全球购物
Java如何格式化日期
2012/08/07 面试题
中软Java笔试题
2012/11/11 面试题
什么是Assembly(程序集)
2014/09/14 面试题
护士个人简历自荐信
2013/10/18 职场文书
施工人员岗位职责
2013/12/12 职场文书
教师实习自我鉴定
2013/12/14 职场文书
初一家长会邀请函
2014/01/31 职场文书
人事专员职责
2014/02/22 职场文书
优秀护士先进事迹
2014/05/08 职场文书
优秀管理者事迹材料
2014/05/22 职场文书
2015年教师见习期工作总结
2015/05/20 职场文书
感恩的心主题班会
2015/08/12 职场文书
CSS3 菱形拼图实现只旋转div 背景图片不旋转功能
2021/03/30 HTML / CSS