2014-01-16 80 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 
    ]