Javascript AngularJS:观察维度的最佳方式?
所以,我想出了一些解决方案,但我仍然不确定什么是最好的。首先作为参考,我可以找到一个类似的问题,尽管它有点老了。这是给以后阅读本文的人的: 目标 我的应用程序中有部分需要响应高度元素。我希望在UI/指令层以最快、最具视觉吸引力的方式实现这一点,而无需显式广播更改事件 选项一:指令 一个简单的指令可以记录每个摘要循环上的维度(并调整事件大小) 问题:变化传播速度不够快,视觉滞后明显 解决方案:使用间隔调用Javascript AngularJS:观察维度的最佳方式?,javascript,css,angularjs,dom,angularjs-directive,Javascript,Css,Angularjs,Dom,Angularjs Directive,所以,我想出了一些解决方案,但我仍然不确定什么是最好的。首先作为参考,我可以找到一个类似的问题,尽管它有点老了。这是给以后阅读本文的人的: 目标 我的应用程序中有部分需要响应高度元素。我希望在UI/指令层以最快、最具视觉吸引力的方式实现这一点,而无需显式广播更改事件 选项一:指令 一个简单的指令可以记录每个摘要循环上的维度(并调整事件大小) 问题:变化传播速度不够快,视觉滞后明显 解决方案:使用间隔调用 选项二:$interval 我用$interval调用尝试了同样的方法,但CPU使用率出人
选项二:$interval 我用$interval调用尝试了同样的方法,但CPU使用率出人意料地高,即使在我反转了控制并跟踪了由value监视的简单根集合中的元素之后(避免了指令的多个实例产生的并发计时器) 除了我的环境中一些与GC相关的问题(我目前没有看到任何提示),是否有更好的方法来创建这种流体布局 拟议的解决方案/问题 我的第一个想法是创建一个并发的$digest循环,以有效地监视DOM作为一个整体的任何视觉变化。例如,是否有可能高效地迭代所有计算样式,以生成可由值监视的廉价散列?每次添加和/或更改相关的计算样式时,可以相对便宜地触发的东西 在我构建和分析它之前,有人能评论一下它是否真实,或者首先抽象/重构resize触发器是否更有意义 在1.2.9中,关于实现这一目标的首选方法还有其他想法吗 [编辑]另一个可能更简单的问题:是否可以通过Javascript以计算效率高的方式提供1-200ms的实际刷新率?如果是这样,是Angular的$interval,还是“VanillaJS”实现更高效?请查看
我想这正是你所需要的。你可以观察窗户的宽度等等。我不确定它是否也适用于身高,但你可以扩展它。不幸的是,这个问题没有得到我想要的那么多关注。。。我没有时间写一个详细的背景说明,剖析器截图等,但我确实找到了一个解决方案,我希望这能帮助其他人处理同样的问题
结论 任何实际的中大型应用程序中的$digest循环都无法处理100ms的刷新 考虑到
setInterval
的要求,我只是完全绕过了循环,而只是在检测到不同维度时才选择广播状态更改(使用offsetWidth/Height
本机属性)
使用单个$root
范围清单以100ms的间隔运行,在我的2.4Ghz i7 2013 MBP上使用约10.2%的活动选项卡CPU,这是我所测试过的最好的结果,与使用$interval
的约84%相比,这是可以接受的
欢迎任何评论和批评,否则,这里是自我包含的指令!显然,您可以创造性地使用范围和/或属性来定制观察者,但为了继续讨论这个主题,我尝试省略任何多余的代码
它将监视一个元素的大小变化,并将其绑定到您选择的一个范围属性,用于具有线性复杂度的N个元素。我不能保证这是实现这一点的最快/最好的方法,但这是我能够快速开发的跟踪状态无关的DOM级别维度更改的最快实现:
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);
}
};
}]);
但是除了基本的响应能力(水平/窗口大小)之外,这并没有做任何事情,坦白地说,仅凭引导和CSS媒体查询就更容易实现。。。我们的目标是实时跟踪动态定位元素的尺寸,并具有最高的计算效率(比如,一组约10-200个节点的渲染组),具有双侦听器(
$watch
和window.onresize
),这两者之间是否存在任何并发/循环周期问题?谢谢,很快,这在HTML中是如何使用的?不知道在引用中放什么
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);
}
};
}]);