项目中Angularjs遇到的问题和优化总结
2017-02-26 15:30
246 查看
项目中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.使用双向数据绑定搭建多级联动操作
双向数据绑定搭建多级联动操作9关于ui-router内存泄露问题的github上讨论
路由内存泄露问题相关文章推荐
- 项目中Angularjs遇到的问题和优化总结
- 项目中Angularjs遇到的问题和优化总结
- 项目开发中经常遇到的一些问题总结
- 公司项目开发过程中遇到的问题总结!
- 异步下载图片小项目中遇到的问题总结
- maven构建项目自动部署到tomcat中遇到的各种sb问题总结
- 项目开发遇到的问题及其解决.总结
- 项目上线后遇到的问题总结
- 做完了工作以来的第一个项目 总结了一下在这个项目中遇到的问题 备份一下
- 重温SportsStore项目所遇到的问题总结
- Github开源项目SlidingMenu学习遇到的问题总结
- [项目过程中所遇到的各种问题记录]学习篇——对工作以来的学习过的开源项目进行总结—DiscuzNt
- 初触cocos2d-x,win32平台搭建以及创建第一个cocos2d-x项目遇到问题总结
- asp.net c#.net项目中使用总结,遇到的各个问题的汇总
- PDA(WinCE)项目开发中遇到的问题及解决方法总结
- 前段时间做项目中,遇到的问题以及解决办法的总结(一)
- struts2总结(自己做项目时遇到的问题加上一些网上的资料)
- 总结python+Django+mysql项目遇到的一些问题
- 项目管理遇到的问题总结
- 从代码都发布遇到的问题总结(C#调用非托管dll文件,部署项目)