您的位置:首页 > Web前端 > AngularJS

项目中Angularjs遇到的问题和优化总结

2017-06-08 22:52 176 查看


项目中Angularjs遇到的问题和优化总结

由于本项目最低需要兼容ie8浏览器,所以在版本选择上选择Angularjs1.2版本。


1.ng-if/ng-switch与ng-show/ng-hide区别选择

ng-show/ng-hide是通过修改CSS样式方式控制元素显示与隐藏,对应的DOM元素会一直存在于当前页面中,本质是CSS属性操作display:none;display:block,而ng-if根据表达式的值动态的在当前的页面中添加删除页面元素。如果赋值表达式的值为false,那么这个元素就会从页面中删除,否则会添加一个元素。ng-if创建元素时用的是被它编译后的代码,如果ng-if内部的代码被其它方式修改过,那么修改只会对本次展现有效,页面元素重新渲染后修改效果会消失,而ng-show/ng-hide则能够保留dom元素上次修改后的状态。
在作用域方面,两者也存在差异:当一个元素被ng-if从DOM中删除时,与其关联的作用域也会被销毁。而且当它重新加入DOM中时,则会生成一个新的作用域,而ng-show和ng-hide则不会。

项目中由于需要多个列表数据较多,如果频繁的重建和删除DOM元素,将十分耗性能,所以在性能考虑上使用ng-show。

当然也有另一种情况,那就是一些长列表数据,可能有一些东西是通过默认隐藏,点击显示的形式展现的.而这部分可控制显隐的内容中也会伴随很多数据绑定.这个在页面渲染的时候非常影响性能.(angular建议一个页面的数据绑定不超过2000个,假如现在有一个页面直接绑定了2000个model,然后你加载,会发现非常卡.如果你将每100的model设置为ng-show,默认情况下不显示,你会发现还是很卡.)然后你将所有的ng-show换成ng-if,你会发现性能瞬间快的像两个应用.原因在ng-show还是会执行其中的所有绑定,ng-if则会在等于true,也就是显示的时候再去执行其中的绑定.这样一来性能就有很大的提高.

ng-show = false 

ng-show=true 

ng-if = true 

ng-if = false 

angular.module(“app”,[]).controller(“MainCtrl”,function($scope){ 

});

示例demo


2 双向数据绑定{{}}使用刷新出现{{}}

由于后台数据问题没有访问成功,前台界面就不需要显示{{}},用ng-bind指令代替{{}}


3 rootScrope以及和scope的区别?

rootScrope页面所有scope的父亲。
如何产生rootScope和scope

step1:Angular解析ng-app然后在内存中创建$rootScope。

step2:angular回继续解析,找到{{}}表达式或者ng-bind指令,并解析成变量。

step3:接着会解析带有ng-controller的div然后指向到某个controller函数。这个时候在这个controller函数变成一个$scope对象实例。


4 使用路由 去除url中总是默认带有”#”

在设置route的时候,开启HTML5模式.
angular.module('router', ['ngRoute'])
.config(['$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);   // 设置一下这句即可
}
]);


5 页面快速定位元素位置

一般来讲页面内通过这样的形式就可以结合js代码,实现快速定位.在angular中也是通过类似的原理实现,代码如下:
var old = $location.hash();
$location.hash('batchmenu-bottom');
$anchorScroll();
$location.hash(old);


这样写是因为直接location.hash会导致url变化,页面跳转,所以加了防止跳转的代码.


6 使用路由切换不同模块需要全显示

在使用路由开发时,切换路由将会重新remove上一个模块的div,重新添加下个模板。一般项目中可能都会有需求需要固定头部header和sidebar,这样不同模板之间切换每次变化的都是ui-route(原生ngRoute)内的ui-view(ng-view)的template。如果有一个页面需要浏览器显示整个完整的页面,不包括头部和侧边栏。
可以使用ng-if绑定变量控制头部和侧边栏的显示和隐藏。

1.可以直接在service中做一个全局变量进行控制

2.消息广播方式:具体变量的绑定可以在controller中通过scope.emit向上发送一个消息,然后页面的controller通过scope.on监听消息,一旦收到消息,改变变量值。


7 ng-repeat的使用

项目中有个需求需要实时跟新列表数据list,按照传统的做法是使用定时器每隔10000ms向后台发送请求,和原来数据对比,数据跟新后首先移除本来的列表div,然后重新动态添加新数据列表,一般不使用任何框架的情况下,都是用jQuery进行操作,但是这里有一个问题,就是实时数据量很大,就要不断的dom的操作,而dom操作是十分消耗性能的。

考虑到以上问题,采用Angular内部服务http进行后台数据请求,同时在控制器中使用scope.$watch()监听数据的变化,和旧数据对比是否发生变化,然后使用内部指令ng-repeat便利数组生成Dom元素,进行列表显示。

ng-repeat在使用过程中还要考虑一个性能问题,这个坑也要十分注意,不然对整体性能的提升作用不大。

为了方便说明,这里举一个小小例子。
<body ng-app="myApp" ng-controller="myCtrl">
<button ng-click="request()">重新请求新数据</button>
<ul>
<li ng-repeat="data in records">{{data.name}}</li>
</ul>
</body>
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
var data1 = [];
var data2 = [];
for (var i = 0; i < 3; i++) {
data2[i] = data1[i] = {
id: i,
name: "jay: " + i
};
}

for (var i = 0; i < 3; i++) {
data2[i] = {
id: "id"+i,
name: "sum: " + i
};
}
$scope.records = data1;
$scope.request = function () {
// 模仿从服务器加载新数据
var result = data2;
// 直接重新赋值给 records
$scope.records = result;
};
});
</script>


开始展示data1数组列表,点击请求数据后重新向$scope.records中替换数据data2,data1和data2长度相同但是内容不同。重新请求数据,查看ng-repeat中源码可以发现,当ng-repeat中的数组内容发生变化时,会将原来的dom删除,根据新的数据重新生成新的dom元素。
// remove existing items
for (key in lastBlockMap) {
// lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
if (lastBlockMap.hasOwnProperty(key)) {
block = lastBlockMap[key];
elementsToRemove = getBlockElements(block.clone);
$animate.leave(elementsToRemove);
forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
block.scope.$destroy();
}
}




在代码中进行断点进入操作,发现即使使用了ng-repeat指令,还是对dom进行了频繁的消除和重建操作,对性能的提升并没有多大作用,我们不会想为什么ng-repeat不能利用已经存在的dom元素去跟新新加载的数据,而不是频繁的remove和create。

查看ng-repeat的使用API后发现,ng-repeat内有一个track by $index代码。
<li ng-repeat="data in records track by $index">{{data.name}}</li>


加上这段代码之后,重新刷新回到我们的例子,发现点击请求加载数据后,没有进入上那段代码之中了。这是为何呢?

删除
track by $index
代码,重新操作添加前demo,可以看到ng-repeat往数组里的每个新添加的元素加了一个$$hashkey属性,这个key是由Angualr内部的nextUid()方法生成,类似数据库的自增id号,使用字符串进行唯一标示。这下明白,为什么dom不能重用,因为每次替换数组都会导致ng-repeat为每个元素生成一个新的key进行唯一标识,这样就没有办法重用已有的dom元素。 



当使用ng-repeat时要尽量避免对全局列表的刷新。ng-repeat会产生一个$$hashkey属性和一系统唯一的项。这意味着当你调用 scope.listBoundToNgRepeat = serverFetch() 时会引起对整个列表的重新刷新。会通知执行所有的watchers并触发每一个元素,这是非常消耗性能的。这里有两种解决方案。一种是维护两个集合,和带有过虑器(filter)的ng-repeat(基本上需要自定义同步逻辑,因此算法更复杂,可维护性更差),另一种方案是使用track by去指定你自己的key(Angular
1.2 开始支持,只需要很少的同步逻辑)。

添加
track by $index
后,重新查看,发现新添加的数组中没有出现$$hashkey属性,这样ng-repeat就可以将其缓存起来,仅仅对dom中的数据进行替换操作,从而提升性能。 



同时我们查看dom树的跟新状态也能看出是重新创建了dom,还是只是对数据进行了替换。 






8.使用双向数据绑定搭建多级联动操作

双向数据绑定搭建多级联动操作 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: