AngularJS - 绑定到指令resize

时间:2014-01-16 19:05:06

标签: angularjs angularjs-directive

如何在调整指令大小时通知我? 我试过了

element[0].onresize = function() {
            console.log(element[0].offsetWidth + " " + element[0].offsetHeight);
        }

但它没有调用函数

(function() {
'use strict';

// Define the directive on the module.
// Inject the dependencies. 
// Point to the directive definition function.
angular.module('app').directive('nvLayout', ['$window', '$compile', layoutDirective]);

function layoutDirective($window, $compile) {
    // Usage:
    // 
    // Creates:
    // 
    var directive = {
        link: link,
        restrict: 'EA',
        scope: {
            layoutEntries: "=",
            selected: "&onSelected"
        },
        template: "<div></div>",
        controller: controller
    };
    return directive;

    function link(scope, element, attrs) {
        var elementCol = [];

        var onSelectedHandler = scope.selected();

        element.on("resize", function () {
            console.log("resized.");
        });

        $(window).on("resize",scope.sizeNotifier);

        scope.$on("$destroy", function () {
            $(window).off("resize", $scope.sizeNotifier);
        });

        scope.sizeNotifier = function() {
            alert("windows is being resized...");
        };

        scope.onselected = function(id) {
            onSelectedHandler(id);
        };



        scope.$watch(function () {
            return scope.layoutEntries.length;
        },
        function (value) {
            //layout was changed
            activateLayout(scope.layoutEntries);
        });

        function activateLayout(layoutEntries) {


            for (var i = 0; i < layoutEntries.length; i++) {

                if (elementCol[layoutEntries[i].id]) {
                    continue;
                }
                var div = "<nv-single-layout-entry id=slot" + layoutEntries[i].id + " on-selected='onselected' style=\"position:absolute;";
                div = div + "top:" + layoutEntries[i].position.top + "%;";
                div = div + "left:" + layoutEntries[i].position.left + "%;";
                div = div + "height:" + layoutEntries[i].size.height + "%;";
                div = div + "width:" + layoutEntries[i].size.width + "%;";
                div = div + "\"></nv-single-layout-entry>";

                var el = $compile(div)(scope);
                element.append(el);
                elementCol[layoutEntries[i].id] = 1;
            }


        };
    }

    function controller($scope, $element) {

    }
}

      })();

6 个答案:

答案 0 :(得分:15)

scope.$watch与自定义监视功能结合使用:

scope.$watch(
  function () {
    return [element[0].offsetWidth, element[0].offsetHeight].join('x');
  },
  function (value) {
    console.log('directive got resized:', value.split('x'));
  }
)

答案 1 :(得分:13)

您通常希望观看元素的select 'min' as k, min(salary) as v from parent union select 'avg' as k, avg(salary) as v from parent union select 'max' as k, max(salary) as v from parentoffsetWidth属性。使用更新版本的AngularJS,您可以在链接功能中使用offsetHeight

$scope.$watchGroup

但是,您可能会发现以这种方式直接观看元素属性时更新速度很慢。

为了使您的指令更具响应性,您可以使用app.directive('myDirective', [function() { function link($scope, element) { var container = element[0]; $scope.$watchGroup([ function() { return container.offsetWidth; }, function() { return container.offsetHeight; } ], function(values) { // Handle resize event ... }); } // Return directive definition ... }]); 来降低刷新率。以下是以可配置的毫秒速率观察元素大小的可重用服务示例:

$interval

使用这种服务的指令看起来像这样:

app.factory('sizeWatcher', ['$interval', function($interval) {
    return function (element, rate) {
        var self = this;
        (self.update = function() { self.dimensions = [element.offsetWidth, element.offsetHeight]; })();
        self.monitor = $interval(self.update, rate);
        self.group = [function() { return self.dimensions[0]; }, function() { return self.dimensions[1]; }];
        self.cancel = function() { $interval.cancel(self.monitor); };
    };
}]);

请注意app.directive('myDirective', ['sizeWatcher', function(sizeWatcher) { function link($scope, element) { var container = element[0], watcher = new sizeWatcher(container, 200); $scope.$watchGroup(watcher.group, function(values) { // Handle resize event ... }); $scope.$on('$destroy', watcher.cancel); } // Return directive definition ... }]); 事件处理程序中对watcher.cancel()的调用;这可以确保$scope.$destroy实例在不再需要时被销毁。

可以找到一个JSFiddle示例here

答案 2 :(得分:7)

以下是您需要执行的示例代码:

APP.directive('nvLayout', function ($window) {
  return {
    template: "<div></div>",
    restrict: 'EA',
    link: function postLink(scope, element, attrs) {

      scope.onResizeFunction = function() {
        scope.windowHeight = $window.innerHeight;
        scope.windowWidth = $window.innerWidth;

        console.log(scope.windowHeight+"-"+scope.windowWidth)
      };

      // Call to the function when the page is first loaded
      scope.onResizeFunction();

      angular.element($window).bind('resize', function() {
        scope.onResizeFunction();
        scope.$apply();
      });
    }
  };
});

答案 3 :(得分:2)

使用$ watch检测元素大小/位置变化的唯一方法是使用$ interval或$ timeout等常量更新范围。虽然可能,但它可能会成为一项昂贵的操作,并且会严重降低您的应用程序速度。

您可以通过调用来检测元素更改的一种方法 requestAnimationFrame

var previousPosition = element[0].getBoundingClientRect();

onFrame();

function onFrame() {
  var currentPosition = element[0].getBoundingClientRect();

  if (!angular.equals(previousPosition, currentPosition)) {
    resiszeNotifier();
  }

  previousPosition = currentPosition;
  requestAnimationFrame(onFrame);
}

function resiszeNotifier() {
  // Notify...
}

这是一个Plunk展示了这一点。只要你移动盒子,它就会保持红色。

http://plnkr.co/edit/qiMJaeipE9DgFsYd0sfr?p=preview

答案 4 :(得分:0)

Eliel的回答略有不同,对我有用。在directive.js中:

      $scope.onResizeFunction = function() {
      };

      // Call to the function when the page is first loaded
      $scope.onResizeFunction();

      angular.element($(window)).bind('resize', function() {
        $scope.onResizeFunction();
        $scope.$apply();
      });

我打电话

    $(window).resize();

来自我的app.js.该指令的d3图表现在调整大小以填充容器。

答案 5 :(得分:0)

以下是我对此指令的看法(使用Webpack作为捆绑器):

module.exports = (ngModule) ->

  ngModule.directive 'onResize', ['Callback', (Callback) ->
    restrict: 'A'
    scope:
      onResize: '@'
      onResizeDebounce: '@'
    link: (scope, element) ->
      container = element[0]
      eventName = scope.onResize || 'onResize'
      delay = scope.onResizeDebounce || 1000
      scope.$watchGroup [
        -> container.offsetWidth ,
        -> container.offsetHeight
      ], _.debounce (values) ->
        Callback.event(eventName, values)
      , delay
  ]