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

angularjs中使用ng-repeat的注意点

2018-01-16 11:10 507 查看

1、ng-repeat的数据不能出现重复项问题

通常情况下,ng-repeat的数据是不可以重复的,否则就会报错。原因是angular需要一个唯一值可以与生成的dom绑定,以便追踪.

解决方案:
<div ng-repeat="(key,value) in datas track by key"></div>


2、ng-repeat的性能问题

AngularJs 的 ng-repeat 让我们非常方便的遍历数组/对象来生成 Dom 元素,然后在使用过程中也需要注意性能问题。

原理:在项目中我们使用 ng-repeat 加载完一个列表后,如果再次请求数据,当 ng-repeat 的数组被替换时, 它默认并不会重新利用已有的 Dom 元素,而是直接将其全部删除并重新生成新的数组 Dom 元素。而频繁的操作dom显然是很不友好的。为什么 ng-repeat 不能利用已有的 dom 元素去更新数据呢?因为你没有把数组元素的标识属性告诉它,那么两次替换的时候它就没办法追踪了。我们可以看到 ng-repeat 往数组里每个元素加了一个 $$hashKey 的属性:



这个 key 是由 Angular 内部的 nextUid() 方法生成,类似数据库自增,但是是使用字符串。

现在我们明白了,因为每次替换数组都会导致 ng-repeat 为每个元素生成一个新 key, 所以根本没办法重用已有的 Dom 元素,那么我们可以使用下边的语法来避免这个问题:

<div ng-controller="Test">
<button ng-click="request()">请求新数据</button>
// 使用 track by 标识
<div ng-repeat="user in users track by user.id">
{{user.name}}
</div>
</div>


这样 ng-repeat 就用将其缓存起来啦,当然可能你的数组元素没有一个标识属性,如果元素数量不多那么可以接受,不然还是建议你手动为其生成一个标识属性,类似于id。

3、ng-options遇到的问题

ng-options的使用原理和ng-repeat 是一致的,都可以很方便的遍历数组/对象。先来看一组代码:

$scope.selectDatas = [
{
id: "1",
name: "apple"
}, {
id: "2",
name: "origin"
}, {
id: "3",
name: "bananer"
},{
id:"4",
name:"pear"
}];


html中展示:

<select ng-change="editChangeSelectDatas()"  ng-options="obj.name for obj in selectDatas" ></select>


这样就可以将下拉列表完美的展示出来了。当我们想下拉列表默认选中一个时,代码如下:

$scope.selectDataSelected = {name:"pear",id:"4"};


<select ng-change="editChangeSelectDatas()"  ng-options="obj.name for obj in selectDatas" ng-model="selectDataSelected"></select>


此时,默认选中pear,非常完美!然而当我在去变换选择其他项时,会发现下拉列表始终展示的是我默认设置为显示的那一项,what should i do?

原因:ng-repeat指令为集合中的每项都实例化一个模块。每个模块都有自己的scope,也就是说ng-model绑定的selectDataSelected的作用域已经发生变化,你在通过ng-repeat去设置scope.selectDataSelected=scope.selectDatas[i],是无效的。因为每一个$scope.selectDataSelected都有自己的作用域。

解决方案:

$scope.obj = {selectDataSelected :{name:"pear",id:"4"}}


<select ng-change="editChangeSelectDatas()"  ng-options="obj.name for obj in selectDatas" ng-model="obj.selectDataSelected"></select>


这样他始终绑定的都是obj对象下的selectDataSelected,就可以避免类似的问题了。

另外使用ng-model双向绑定的时候,建议去绑定他的对象属性比如ng-model=”obj.name”,而不是ng-model=”name”,这样可避免出现此类问题。

4、ng-repeat如何在渲染完成后再去执行脚本

ng-repeat遍历渲染完页面后如何去执行某个操作??接下来需要我们了解一下ng-repeat循环中的几个特殊变量。

变量类型描述
$indexnumber当前索引。
$firstboolean当循环的对象存在第一项时为true。
$middleboolean当循环的对象存在中间项时为true。
$lastboolean当循环对象存在最后一项时为true。
$evenboolean循环的对象在当前位置的索引是偶数则为true。
$oddboolean循环的对象在当前位置的索引是奇数则为true。
index会随着每次遍历(从0开始)递增,当遍历到最后一个时,last的值为true,so,通过判断last的值来监听ng−repeat的执行状态,怎么在遍历过程中拿到last的值:自定义指令

<div id="box">
<span ng-repeat="item in data" repeat-finish="renderFinish()">{{item.str}}</span>
</div>


app.directive('repeatFinish',function(){
return {
link: function(scope,element,attr){
console.log(scope.$index);
//也可使用scope.$watch('$last',function(){});
if(scope.$last == true){
console.log('ng-repeat执行完毕')
scope.$eval( attr.repeatFinish )
}
}
}
})
//controller里对应的处理函数
$scope.renderFinish = function(){
console.log('渲染完之后的操作')
}


总结:在第一个和第二个问题中反复用到了track by来解决问题,简单了解一下,angular需要一个唯一值可以与生成的dom绑定,以便追踪,因此track by 后面跟的值一定是唯一的,如果一旦出现重复数据,均会保错(包括如果track by 后面的值为undefined,多个undefined也同样会报错),而orderby是可以出现重复数据的,orderby和track by一起使用的格式为:

<tr ng-repeat="item in $ctrl.indicators | orderBy:'id' track by item._id">


提高性能的同时,进行排序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息