AngularJS:观看尺寸的最佳方式? [英] AngularJS: Best way to watch dimensions?

查看:139
本文介绍了AngularJS:观看尺寸的最佳方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我已经提出了一些解决方案,我还不太清楚什么是最好的。首先参考,有一个类似的问题,我可以找到,虽然它有点老了。在这里,任何人可以稍后阅读:观察角度的维度变化

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆