AngularJS:观看尺寸的最佳方式? [英] AngularJS: Best way to watch dimensions?
问题描述
所以,我已经提出了一些解决方案,我还不太清楚什么是最好的。首先参考,有一个类似的问题,我可以找到,虽然它有点老了。在这里,任何人可以稍后阅读:观察角度的维度变化
So, I've come up with a few solutions to this and I'm still not quite sure what is best. First for reference there is one similar question I could find, though it's a bit old. Here it is for anyone reading this later: Watching dimension changes in Angular
目标
我的应用程序中有部分响应需要高度元素。我想要最快速,最具视觉吸引力的方式在UI /指令层上执行此操作,而无需明确广播的更改事件。
I have portions of my app in which responsive height elements are needed. I want the fastest, most visually appealing way to do this at the UI/directive layer without the need of explicitly broadcasted change events.
选项一:指令
一个简单的指令可以记录每个摘要循环(和调整大小事件)的维度。
A simple directive can record the dimensions on every digest loop (and resize event)
return {
scope: {
size: '=ngSize'
},
link: function($scope, element, attrs) {
var windowEl = angular.element($window),
handler = function() {
if ($scope.size &&
element.outerWidth() === $scope.size.width &&
element.outerHeight() === $scope.size.height) return false;
$scope.size = {
width: element.outerWidth(),
height: element.outerHeight()
};
};
windowEl.on('resize', function() {
$scope.$apply(handler);
});
$root.$watch(function() { return [element.outerWidth(), element.outerHeight()] }, handler, true);
}
};
问题:更改速度不够快,视觉延迟
Problem: The change doesn't propagate quickly enough and visual lag is noticeable.
解决方案:使用间隔调用
选项二:$ interval
我尝试使用$ interval调用相同的东西,令人惊讶的是,即使在我反转控制之后,仍然追踪了一个简单的根集合中的元素(由避免由多个指令实例产生的同时计时器)。
I tried the same thing with an $interval call and it worked, but CPU usage was surprisingly high, even after I inverted control and kept track of elements in a simple root collection watched by value (avoiding concurrent timers produced by multiple instances of the directive).
除了我环境中与GC相关的一些问题(我目前看不到任何建议),可能会有更好的方法来创建这种流体布局?
Aside from some GC-related issue in my environment (I don't see anything that suggests this currently), might there be a better approach to creating this kind of fluid layout?
我的第一个想法将是一种创建并发$ digest循环的方式,以便有效地监视DOM作为整体的任何视觉变化。有可能有效地迭代所有计算的样式,例如,生成可以通过值观看的廉价散列?每次添加和/或更改相关的计算风格时,可以相对便宜地触发某些事情?
My first thought would be a way to create a concurrent $digest loop of sorts, to efficiently monitor the DOM as a whole for any visual changes. Is it possible to efficiently iterate through all computed styles, for example, to produce a cheap hash that can be watched by value? Something that can be triggered relatively inexpensively every time a relevant computed style is added and/or changed?
在构建和配置文件之前,有人可以评论它是否均匀或者如果简单地更有意义的是抽象/重构resize触发器,首先呢?
Before I build and profile it, could someone comment as to whether it's even realistic, or if it simply makes more sense to abstract/refactor the resize triggers in the first place?
任何其他想法在 1.2.9 ?
另一个或许更简单的问题是:甚至可以提供逼真的刷新率通过JavaScript以1-200ms计算效率的方式?如果是这样,那么这个方法是Angular的$间隔,还是可以使VanillaJS的实现效率更高?
[edit] An alternate, perhaps simpler question: is it even possible to provide a realistic refresh rate of 1-200ms via Javascript in a computationally-efficient manner? If so, would that way be Angular's $interval, or could a 'VanillaJS' implementation be more efficient?
推荐答案
没有像我想要的那样受到太多的关注...我没有时间用背景,剖析器截图等来编写详细的解释,但是我找到了一个解决方案,我希望这有助于别人交易同样的问题。
Unfortunately this question didn't get as much attention as I would have liked... And I don't have time to write a detailed explanation with background, profiler screenshots, etc. But I did find a solution, and I hope this helps someone else dealing with the same issue.
$ digest在任何现实的中型大型应用程序中的循环将无法处理100ms的刷新。
The $digest loop in any realistic medium-large application will not be able to handle a refresh of 100ms.
鉴于 setInterval
我完全绕过了循环,而是仅在检测到不同的维度时才使用广播状态更改(使用 offsetWidth / Height
本机属性)。
Given the requirement of setInterval
I simply bypassed the loop entirely, instead opting to broadcast a state change only when differing dimensions are detected (using the offsetWidth/Height
native properties).
使用单个 $ root
范围清单以100ms的间隔运行可以给我最好的结果,已经测试过,在我的2.4Ghz i7 2013 MBP上〜〜10.2%的活动选项卡CPU可以接受,相对于 $ interval
的〜84%。
Running at a 100ms interval with a single $root
scope manifest is giving the best results of anything I've tested, with ~10.2% active-tab CPU on my 2.4Ghz i7 2013 MBP--acceptable compared to the ~84% with $interval
.
欢迎任何评论和评论,否则,这里是自包含的指令!显然,您可以通过范围和/或属性获得创造性来自定义观察者,但为了保持主题,我尝试省略任何多余的代码。
Any comments and critiques are welcome, otherwise, here is the self-contained directive! Obviously you can get creative with the scope and/or attributes to customize the watchers, but in the interest of staying on topic I've tried to omit any superfluous code.
它将监视&将元素上的大小更改绑定到您选择的范围属性,对于具有线性复杂性的N个元素。我不能保证这是最快/最好的方法,但这是我可以快速开发的最快的实现,可以跟踪与状态无关的DOM级维度更改:
It will monitor & bind size changes on an element to a scope property of your choosing, for N elements with a linear complexity. I can't guarantee it's the fastest/best way to do this, but it's the fastest implementation I could develop quickly that tracks state-agnostic DOM-level dimension changes:
app.directive('ngSize', ['$rootScope', function($root) {
return {
scope: {
size: '=ngSize'
},
link: function($scope, element, attrs) {
$root.ngSizeDimensions = (angular.isArray($root.ngSizeDimensions)) ? $root.ngSizeDimensions : [];
$root.ngSizeWatch = (angular.isArray($root.ngSizeWatch)) ? $root.ngSizeWatch : [];
var handler = function() {
angular.forEach($root.ngSizeWatch, function(el, i) {
// Dimensions Not Equal?
if ($root.ngSizeDimensions[i][0] != el.offsetWidth || $root.ngSizeDimensions[i][1] != el.offsetHeight) {
// Update Them
$root.ngSizeDimensions[i] = [el.offsetWidth, el.offsetHeight];
// Update Scope?
$root.$broadcast('size::changed', i);
}
});
};
// Add Element to Chain?
var exists = false;
angular.forEach($root.ngSizeWatch, function(el, i) { if (el === element[0]) exists = i });
// Ok.
if (exists === false) {
$root.ngSizeWatch.push(element[0]);
$root.ngSizeDimensions.push([element[0].offsetWidth, element[0].offsetHeight]);
exists = $root.ngSizeWatch.length-1;
}
// Update Scope?
$scope.$on('size::changed', function(event, i) {
// Relevant to the element attached to *this* directive
if (i === exists) {
$scope.size = {
width: $root.ngSizeDimensions[i][0],
height: $root.ngSizeDimensions[i][1]
};
}
});
// Refresh: 100ms
if (!window.ngSizeHandler) window.ngSizeHandler = setInterval(handler, 100);
// Window Resize?
// angular.element(window).on('resize', handler);
}
};
}]);
这篇关于AngularJS:观看尺寸的最佳方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!