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循环中的几个特殊变量。
变量 | 类型 | 描述 |
---|---|---|
$index | number | 当前索引。 |
$first | boolean | 当循环的对象存在第一项时为true。 |
$middle | boolean | 当循环的对象存在中间项时为true。 |
$last | boolean | 当循环对象存在最后一项时为true。 |
$even | boolean | 循环的对象在当前位置的索引是偶数则为true。 |
$odd | boolean | 循环的对象在当前位置的索引是奇数则为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">
提高性能的同时,进行排序。