2014-01-16 61 views
21

如何在指令调整大小时通知我? 我试图AngularJS - 绑定到指令调整大小

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) { 

    } 
} 

     })(); 
+0

我试图理解的代码的目的,但它是很难我。我已经消除了你的代码的JQuery依赖,你可以在这里查看:http://jsfiddle.net/U3pVM/2669/ –

+0

我只是试图在指令的元素被调整大小时收到通知。我可以在整个页面上听,但我想知道elemnt何时导致指令移动 –

+0

@ li-raz:[我的回答](http://stackoverflow.com/a/23031644/434989)完全可以实现:-) – epegzz

回答

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(); 
     }); 
    } 
    }; 
}); 
+15

如果只有指令get被调整大小,但不是窗口本身,这将不起作用。 – epegzz

+0

绑定正在为我工​​作...虽然我不认为你需要调用应用 –

14

使用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

我试过这个,但它通常会显示我旧的值。我有一个可以隐藏或使用按钮显示的边栏,当我点击时,摘要循环发生,手表功能告诉我元素的大小没有变化,然后元素被调整大小,在下一个循环中拾取,这会导致一个小故障。有任何想法吗? –

+1

@HernanRajchert(以及其他未来的读者),这是因为_ [clientHeight](https://developer.mozilla.org/en-US/docs/Web/API/Element.clientHeight)可以计算为CSS高度+ CSS填充 - 水平滚动条的高度(如果存在)._你想要的是[.offsetHeight](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement.offsetHeight)。看着'element [0] .offsetHeight'(和宽度)应该工作。 –

+0

@JordanCarroll对我来说,使用offsetHeight而不是clientHeight并没有解决问题。 – nardnob

2

使用$ watch可以检测元素上的大小/位置变化的唯一方法是如果您使用诸如$ interval或$ timeout之类的方法不断更新范围。虽然有可能,但它可能会变成一项昂贵的操作,并且会降低您的应用速度。

您可以通过调用 ​​来检测元素的变化。

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

12

您通常想要观看的元素的offsetWidthoffsetHeight性能。随着越来越多的新版本AngularJS的,你可以在你的链接功能使用$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事件处理程序;这可确保$interval实例在不再需要时被销毁。

JSFiddle示例可以找到here

+3

任何想要使用这种方法的人都考虑用'$ interval(self.update,rate,0,false)'替换'$ interval(self.update,rate);'',它明确表示不会在最后调用$ apply 。否则,将在每个间隔回调函数调用中调用范围的摘要。你可以通过$ scope来检查。$ watch(function(){console.log(“invalidated”);});' –

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图表现在调整大小以填充容器。

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 
    ]