Html AngularJS:观察高度变化的更好方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19048985/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AngularJS: Better way to watch for height change
提问by Scheintod
I'm having the old variable height navigation problem: A position: fixes
navigation on top and a content with margin-top: $naviHeight
below.
The navigation can change height when data is loaded asynchronously and so the content's margin has to change with it.
我有旧的可变高度导航问题:position: fixes
顶部导航和margin-top: $naviHeight
下面的内容。异步加载数据时,导航可以更改高度,因此内容的边距必须随之更改。
I want this to be self contained. So no code where the data is loaded but only in the involved html-elements/directives.
我希望这是自包含的。所以没有加载数据的代码,而只在涉及的 html-elements/directives 中。
Currently I'm doing it in AngularJS 1.2.0 with a timer like this:
目前我正在 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();
}
}
} ] )
This has the obvious drawback of using the timer(which i feel kind of ugly) and a certain delay after the navigation resizeduntil the content is moved.
这具有使用计时器的明显缺点(我觉得这有点难看),并且在导航调整大小直到内容被移动之前会有一定的延迟。
Is there a better way to do this?
有一个更好的方法吗?
回答by AlwaysALearner
This works by registering a watcher in emHeightSource
which is called every $digest
. It updates the __height
property which is in turn watched in emHeightTarget
:
这是通过注册一个emHeightSource
名为 every的观察者来实现的$digest
。它更新__height
属性,而后者又被监视emHeightTarget
:
/*
* 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();
} );
}
}
} )
回答by Dor Cohen
You can monitor height change of your element without using Div, just writing a $watch
statement:
您可以在不使用 Div 的情况下监控元素的高度变化,只需编写一条$watch
语句:
// Observe the element's height.
scope.$watch
(
function () {
return linkElement.height();
},
function (newValue, oldValue) {
if (newValue != oldValue) {
// Do something ...
console.log(newValue);
}
}
);
回答by Cherniv
May be you should watch for $window
' dimensions changes , something like:
可能你应该注意$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...
})
}
}
} ] )
回答by Adamy
I used a combination of $watch and resize event. I found without scope.$apply(); in resize event, the height changes on the element is not always picked up by $watch.
我使用了 $watch 和 resize 事件的组合。我发现没有 scope.$apply(); 在调整大小事件中,元素的高度变化并不总是被 $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();
});
};
回答by Jamie Pate
This approach avoids (potentially) triggering a reflow
every digest cycle. It only checks elem.height()
/after/ the digest cycle is over, and only causes a new digest if the height has changed.
这种方法避免(可能)触发reflow
每个摘要循环。它只检查elem.height()
/after/ 摘要循环结束,并且只有在高度发生变化时才会产生新的摘要。
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
)
回答by devsnd
I wrote another timer based variant that can be bound to the scope, because, as Jamie Pate correctly stated, direct DOM access inside the digest cycle is not a very good idea.
我编写了另一个可以绑定到作用域的基于计时器的变体,因为正如 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();
}
};
}
Now you can bind it on any element:
现在你可以将它绑定到任何元素上:
<img size-watcher size-watcher-height="myheight">
<div style="height: {{ myheight }}px">
So the div always keeps (with a latency of a second) the same height as the image.
因此 div 始终保持(延迟一秒)与图像相同的高度。
回答by user3255557
This approach watches an elements height and width and assigns it to a variable on the scope provided on your elements attribute
这种方法监视元素的高度和宽度,并将其分配给元素属性提供的范围内的变量
<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);
}
}])