AngularJS:观察高度变化的更好方法

我有旧的variables高度导航问题:一个position: fixes导航顶部和margin-top: $naviHeight的内容margin-top: $naviHeight下面。 导航可以在数据asynchronous加载时更改高度,因此内容的边距必须随之改变。

我希望这是自足的。 所以没有代码在哪里加载数据,但只在所涉及的HTML元素/指令。

目前我正在AngularJS 1.2.0中使用这样的计时器:

 /* * Get notified when height changes and change margin-top */ .directive( 'emHeightTarget', function(){ return { link: function( scope, elem, attrs ){ scope.$on( 'heightchange', function( ev, newHeight ){ elem.attr( 'style', 'margin-top: ' + (58+newHeight) + 'px' ); } ); } } }) /* * Checks this element periodically for height changes */ .directive( 'emHeightSource', ['$timeout', function( $timeout ) { return { link: function( scope, elem, attrs ){ function __check(){ var h = elem.height(); if( h != scope.__height ){ scope.__height = h; scope.$emit( 'heightchange', h ); } $timeout( __check, 1000 ); } __check(); } } } ] ) 

这有明显的缺点,使用定时器 (我觉得有点丑)和导航resize后,直到内容移动一定的延迟

有没有更好的方法来做到这一点?

这是通过在emHeightSource注册一个观察者来emHeightSource ,该观察者被称为每个$digest 。 它更新了在__height中依次观察的__height属性:

 /* * Get notified when height changes and change margin-top */ .directive( 'emHeightTarget', function() { return { link: function( scope, elem, attrs ) { scope.$watch( '__height', function( newHeight, oldHeight ) { elem.attr( 'style', 'margin-top: ' + (58 + newHeight) + 'px' ); } ); } } } ) /* * Checks every $digest for height changes */ .directive( 'emHeightSource', function() { return { link: function( scope, elem, attrs ) { scope.$watch( function() { scope.__height = elem.height(); } ); } } } ) 

你可以在不使用Div的情况下监视元素的高度变化,只需要写一个$watch语句:

 // Observe the element's height. scope.$watch ( function () { return linkElement.height(); }, function (newValue, oldValue) { if (newValue != oldValue) { // Do something ... console.log(newValue); } } ); 

可能是你应该看$window的尺寸变化,如:

 .directive( 'emHeightSource', [ '$window', function( $window ) { return { link: function( scope, elem, attrs ){ var win = angular.element($window); win.bind("resize",function(e){ console.log(" Window resized! "); // Your relevant code here... }) } } } ] ) 

我使用$ watch和resize事件的组合。 我发现没有范围。$ apply(); 在resize事件中,元素的高度变化并不总是被$ watch拾取。

  link:function (scope, elem) { var win = angular.element($window); scope.$watch(function () { return elem[0].offsetHeight; }, function (newValue, oldValue) { if (newValue !== oldValue) { // do some thing } }); win.bind('resize', function () { scope.$apply(); }); }; 

这种方法避免(潜在地)触发每个摘要周期的reflow 。 它只检查elem.height() /之后/摘要循环结束,并且只有当高度已经改变时才引起新的摘要。

 var DEBOUNCE_INTERVAL = 50; //play with this to get a balance of performance/responsiveness var timer scope.$watch(function() { timer = timer || $timeout( function() { timer = null; var h = elem.height(); if (scope.height !== h) { scope.$apply(function() { scope.height = h }) } }, DEBOUNCE_INTERVAL, false ) 

我写了另一个基于计时器的variables,可以绑定到范围,因为正如Jamie Pate正确地指出的那样,在摘要循环中直接访问DOM不是一个好主意。

 .directive("sizeWatcher", ['$timeout', function ($timeout) { return { scope: { sizeWatcherHeight: '=', sizeWatcherWidth: '=', }, link: function( scope, elem, attrs ){ function checkSize(){ scope.sizeWatcherHeight = elem.prop('offsetHeight'); scope.sizeWatcherWidth = elem.prop('clientWidth'); $timeout( checkSize, 1000 ); } checkSize(); } }; } 

现在你可以将它绑定在任何元素上:

 <img size-watcher size-watcher-height="myheight"> <div style="height: {{ myheight }}px"> 

所以div始终保持(等待一秒钟的延迟)与图像相同的高度。

这种方法监视元素的高度和宽度,并将其分配给元素属性上提供的作用域的variables

  <div el-size="size"></div> .directive('elSize', ['$parse', function($parse) { return function(scope, elem, attrs) { var fn = $parse(attrs.elSize); scope.$watch(function() { return { width: elem.width(), height: elem.height() }; }, function(size) { fn.assign(scope, size); }, true); } }])