我有一个角作用域包含两个东西:
- 一个大表,有10k行,渲染 需要一秒钟
- 一些小的额外信息在它的顶部固定覆盖标题栏
根据你向下滚动页面/表的程度,我必须更新标题中的一个小信息位;你可以把它想象成一个%计数器,显示你滚动了多远。
为了得到当前的滚动位置,我写了一个指令(你也可以在这里找到它):
app.directive "setWindowScroll", ->
restrict: "E"
scope:
setVariable: "="
link: (scope) ->
$(window).scroll ->
scope.$apply ->
scope.setVariable = $(window).scrollTop()
我的问题是,这使得滚动在表u*非常慢*。这是因为我用我的指令写的变量在范围内的额外信息中,并且当我的$apply
被调用时,改变它似乎会导致角脏检查整个表的变化。
我知道这个滚动永远不会改变我的表中的任何东西,并希望限制我的$apply
影响我的网站的标题部分。
如何使角不脏检查表?
Angular在一个名为digest的进程下进行脏检查。当您调用$scope.$digest()
时,它将传播到$scope
的每个子作用域。要通知angular变化,你通常会执行$scope.$apply()
。在$apply()的末尾,angular对根作用域做一个摘要,它会触发应用中每个作用域的摘要。因此,为了避免在具有大表作用域的作用域中使用digest on,您应该确保它不是额外信息作用域的子作用域,而不是在指令中使用$scope.$apply(),而是使用$scope.$digest()。这可能有点令人困惑,所以我做了一个柱塞,试图显示差异。打开控制台,查看滚动事件和按钮单击的区别:
http://plnkr.co/edit/45gKhAIt0DrozS7f0Bz2?p =
预览// this will only cause a digest in the current scope and its children
angular.element($window).bind('scroll',function(){
$scope.scrollY = $window.scrollY;
$scope.$digest();
})
// this will cause a digest in every scope
angular.element($window).bind('scroll',function(){
$scope.scrollY = $window.scrollY;
$scope.$apply();
})
说了这么多,这是一件非常不寻常的事情——而且可能不是一个好主意,原因有很多(angular不能很好地扩展数千个元素,你不能使用任何angular的事件指令(ngClick等),因为它们都被包裹在$apply中)——但如果你不能在服务器端渲染表格,你可以试试。
我想知道这是否也可能做到,但是-无论如何-您可能要考虑不要一次绘制整个表。
将它(以及angular世界中相关数据/控制器的数量)限制为基于当前滚动位置可见的行+上面和下面的一些缓存行。你仍然可以将所有数据保存在客户端上的数组中,但在任何时候只向Angular公开一小部分数据。
一种方法可能是在angular世界中使用ng-repeat
渲染一个小数组,然后根据滚动位置在这个小角度数组中添加和删除元素。
这样,Angular只知道你数据的一小部分,而且渲染速度会快得多。我认为这应该在一般情况下工作得很好,因为它也更少的工作,浏览器不需要维护一个DOM树和渲染10k行。