加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-17 09:35:47 所属栏目:安全 来源:网络整理
导读:项目中Angularjs遇到的问题和优化总结 由于本项目最低需要兼容ie8浏览器,所以在版本选择上选择Angularjs1.2版本。 1.ng-if/ng-switch与ng-show/ng-hide区别选择 ng-show/ng-hide是通过修改CSS样式方式控制元素显示与隐藏,对应的DOM元素会一直存在于当前页

项目中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上讨论

路由内存泄露问题

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读