如何先过滤数据再使用AngularJS的ng-repeat进行渲染?
Hey there! Let's tackle this problem step by step since you're dealing with a large dataset (50k+ records) and performance is definitely a concern here. Your current approach using a custom filter directly in ng-repeat has two main issues: it runs on every digest cycle (which is slow for huge datasets) and it doesn't persist the filtered results in your scope. Here's how to fix both:
核心解决方案:手动监听过滤条件,将结果存入Scope
Instead of relying on a filter in ng-repeat, we'll listen for changes to your search input, run the filtering logic manually, and store the filtered results in a dedicated scope variable. This way, ng-repeat only renders the already-filtered data, and we avoid redundant computations.
修改后的Controller代码
var app = angular.module('myApp', []); app.controller('MainCtrl', function($scope, $http, $timeout) { // 存储原始完整数据 $scope.materiale = []; // 存储过滤后的结果,供ng-repeat使用 $scope.filteredMateriale = []; // 获取后端数据 $http.get("http:source.php") .then(function(response) { $scope.materiale = response.data.records; // 初始化时默认显示全部数据(可根据需求调整为空) $scope.filterMaterials(); }); // 自定义过滤函数,和你之前的filter逻辑一致 $scope.filterMaterials = function() { // 如果没有过滤条件,直接返回全部数据 if (!$scope.filtru || $scope.filtru.trim() === '') { $scope.filteredMateriale = angular.copy($scope.materiale); return; } var filtered = []; var filtruMatch = new RegExp($scope.filtru, 'i'); // 遍历原始数据执行过滤 for (var i = 0; i < $scope.materiale.length; i++) { var item = $scope.materiale[i]; // 匹配MATKL、MAKTX或MATNR字段 if (filtruMatch.test(item.MATKL) || filtruMatch.test(item.MAKTX) || filtruMatch.test(item.MATNR)) { filtered.push(item); } } // 将过滤结果存入scope $scope.filteredMateriale = filtered; }; // 监听过滤输入的变化,添加防抖优化(避免每次输入字符都立刻触发过滤) var debounceTimer; $scope.$watch('filtru', function(newVal, oldVal) { if (newVal !== oldVal) { // 清除之前的定时器,避免重复执行 if (debounceTimer) { $timeout.cancel(debounceTimer); } // 延迟300ms执行过滤,用户停止输入后再计算 debounceTimer = $timeout(function() { $scope.filterMaterials(); }, 300); } }); });
修改后的HTML代码
<input ng-model='filtru' type="text" placeholder="..."> <tbody ng-repeat="material in filteredMateriale"> <!-- 你的表格内容 --> </tbody>
为什么这能解决你的问题?
- 性能提升:过滤逻辑仅在搜索输入变化时执行(还加了防抖,减少计算次数),而不是AngularJS的每个digest循环都重新计算,这对5万条数据来说差异巨大。
- 结果持久化:过滤后的结果存在
$scope.filteredMateriale中,你可以在控制器的其他地方直接使用这个变量,而不是每次都重新过滤。
针对大数据量的额外优化建议
如果5万条数据即使过滤后还是有性能问题,试试这些方法:
- 后端过滤:把过滤逻辑移到PHP层,前端输入时发送过滤参数给PHP,PHP执行带
WHERE条件的SQL查询后返回过滤后的JSON。这样前端不需要加载全部5万条数据,性能会大幅提升。 - 分页显示:即使过滤后还有上千条数据,分页显示(比如每页50条),只渲染当前页的DOM元素,避免一次性渲染大量节点。
- 虚拟滚动:使用虚拟滚动库,只渲染当前可见区域的列表项,适合长列表场景。
内容的提问来源于stack exchange,提问作者Pwner

