ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] # ng-repeat指令 ## 简介 使用指令复制元素在构建模板内容的过程中,有时需要反复将不同的数据加载到一个元素中,例如,通过`<li>`元素绑定一个数组的各成员。此时,可以使用“ng-repeat”指令,它的功能是根据绑定数组成员的数量,复制页面中被绑定的`<li>`元素,并在复制过程中添加元素相应的属性和方法,通过这种方式,实现数组数据与元素绑定的过程。在使用“ng-repeat”指令复制元素的过程中,还提供了几个非常实用的专有变量,可以通过这些变量来处理显示数据时的各种状态。 * $first,该变量表示记录是否是首条,如果是则返回true,否则返回false。 * $last,该变量表示记录是否是尾条,如果是则返回true,否则返回false。 * $middle,该变量表示记录是否是中间条,如果是则返回true,否则返回false。 * $index,该变量表示记录的索引号,其对应的值从0开始。 * $even,该变量表示记录是否是奇数条,如果是则返回true,否则返回false。 * $odd,该变量表示记录是否是偶数条,如果是则返回true,否则返回false。 ## 基本使用 ~~~html <ul> <!--data为$scope中的数组--> <!--in为关键字--> <!--item为一个变量名,代表data里面的每一个元素--> <li ng-repeat="item in data"> {{item.name}}&nbsp;&nbsp; {{item.sex}}&nbsp;&nbsp; {{item.age}}&nbsp;&nbsp; {{item.score}} </li> </ul> ~~~ ## 使用ng-repeat需要注意的问题 在Angular中,ng-repeat是一个非常重要的内部指令,它的功能是在遍历数组过程中生成DOM元素,实现在页面中展示列表数据中的功能,功能强大、使用简单,但如果使用不当也容易出现一些问题,具体表现如下。 * 在使用过程中,如果有过滤器时,调用$index并不能准确定位到对应的记录。 * 在调用ng-repeat指令重新请求数据,并不是在原来DOM元素中更新数据,而是再次新建DOM元素。 * 在通过ng-repeat指令生成的子元素中,如果通过父的scope对象更新数据时,不能直接更新遍历的数组源,而必须逐个更新。 ## 使用ng-repeat处理办法 ### 有过滤器的情况下使用ng-repeat ### 首先数据会都自带不重复的id ### 在界面显示的情况下,也会使用赋值表达式【item in localData=(data | filter:myfilter) 】 #### index.js ~~~js //创建控制器 angular.module('myapp').controller('my_c', ['$filter', '$scope', function ($filter, $scope) { // 数据 // 一般情况下,我们的数据都会带有独立的ID $scope.data = [ { id: 1, name: 'hzj', sex: '男', age: 18, score: 100 }, { id: 2, name: 'hzj', sex: '男', age: 28, score: 100 }, { id: 3, name: 'hzj', sex: '男', age: 26, score: 100 }, { id: 4, name: 'hzj', sex: '男', age: 30, score: 100 }, { id: 5, name: 'hzj', sex: '男', age: 19, score: 100 }, { id: 6, name: 'hzj', sex: '男', age: 22, score: 100 }, { id: 7, name: 'hzj', sex: '男', age: 18, score: 100 }, { id: 8, name: 'hzj', sex: '男', age: 21, score: 100 }, { id: 9, name: 'hzj', sex: '男', age: 18, score: 100 } ]; //自定义一个filter过滤器的过滤规则 $scope.myfilter = function (item) { return item.age > 25; }; // 删除元素 // item参数为view传递过来的数据里面的某一项 $scope.removeItem = function (item) { //使用angular.forEach方法查询到数组中对应的下 //arrayItem为$scope.data里面的每一项 // index为arrayItem项在$scope.data中的下标 angular.forEach($scope.data, function (arrayItem, index) { if (item.id === arrayItem.id) { //找到元素对应的下标,然后删除元素 $scope.data.splice(index, 1); return; } }); }; }]); ~~~ #### index.html ~~~html <!DOCTYPE html> <!--加载模块--> <html lang="en" ng-app="myapp"> <head> <meta charset="UTF-8"> <title>Title</title> <!--加载样式--> <link rel="stylesheet" href="css/index.css"> <!--加载Angular类库--> <script src="bower_components/angular/angular.min.js"></script> <!--加载模块创建文件--> <script src="js/app.js"></script> <!--加载控制器创建文件--> <script src="js/index.js"></script> </head> <body> <!--加载控制器--> <div ng-controller="my_c"> <!--带过滤的数据--> <table> <thead> <tr> <td>行标</td> <td>id</td> <td>姓名</td> <td>性别</td> <td>年龄</td> <td>分数</td> <td>操作</td> </tr> </thead> <tbody> <!--这里使用了过滤好的数据,原数据为data--> <!--localData=( data |filter:myfilter)--> <tr ng-repeat="item in localData =( data |filter:myfilter) "> <td>{{$index}}</td> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.sex}}</td> <td>{{item.age}}</td> <td>{{item.score}}</td> <td> <button ng-click="removeItem(item)">删除</button> </td> </tr> </tbody> <tfoot> <tr> <td colspan="7">总人数为:{{localData.length}}</td> </tr> </tfoot> </table> <hr> <!--原始数据--> <table> <thead> <tr> <td>行标</td> <td>id</td> <td>姓名</td> <td>性别</td> <td>年龄</td> <td>分数</td> </tr> </thead> <tbody> <!--这里使用的是原数据--> <tr ng-repeat="item in data"> <td>{{$index}}</td> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.sex}}</td> <td>{{item.age}}</td> <td>{{item.score}}</td> </tr> </tbody> <tfoot> <tr> <td colspan="6">总人数为:{{data.length}}</td> </tr> </tfoot> </table> </div> </body> </html> ~~~ #### 结果 ![](https://box.kancloud.cn/2016-09-10_57d3f729162f3.png) #### 点击删除ID为3的元素之后 ![](https://box.kancloud.cn/2016-09-10_57d3f72aaa88b.png) ### 使用track by排序数据中的唯一id属性 在使用ng-repeat指令显示列表数据时,如果需要更新数据,那么页面中原有的DOM元素在更新过程中并不会被重用,而是会被删除,再重新生成与上次结构一样的元素。反复生成DOM元素对页面的加载来说,并不是一件好事,它不仅会延迟数据加载的速度,而且非常浪费页面资源。为了解决这种现象,我们在使用ng-repeat指令更新数据时,需要使用track by对数据源进行排序,排序的字段为不可重复的id。放心每个数据库里面的数据都会有id属性 ~~~html <tr ng-repeat="item in localData =( data |filter:myfilter | orderBy:'-age' ) track by item.id"> <td>{{$index}}</td> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.sex}}</td> <td>{{item.age}}</td> <td>{{item.score}}</td> <td> <button ng-click="removeItem(item)">删除</button> </td> </tr> ~~~ ~~~html <tr ng-repeat="item in data track by item.id"> <td>{{$index}}</td> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.sex}}</td> <td>{{item.age}}</td> <td>{{item.score}}</td> </tr> ~~~ ### ng-repeat结束事件【这里仅仅是参考,到了中级部分会出现自定义指令】 Angular并没有ng-repeat结束事件监听,我们必须自己自定义一个指令来完成 ~~~js //自定义指令repeatFinish angular.module('myapp').directive('hzjEndRepeat', ['$timeout', function ($timeout) { return { restrict: 'A', link: function (scope, element, attr) { //scope为repeat出来的每个dom的作用域 //element为repeat当前的元素 //attr为属性 if (scope.$last === true) { //延迟一些执行 $timeout(function () { //像父亲发送事件 $scope.$emit('hzjEndRepeat'); }); } } }; }]); ~~~ ~~~html <div class="filter_row clearfix" ng-repeat="item in filterType" hzj-end-repeat> </div> ~~~