古い可変高ナビゲーション問題があります:A position: fixes
上部のナビゲーションとmargin-top: $naviHeight
未満。データが非同期にロードされるとナビゲーションの高さが変わる可能性があるため、コンテンツのマージンもそれに合わせて変更する必要があります。
これが自己完結型であることを望みます。したがって、データがロードされるコードはありませんが、関連するhtml-elements/directivesにのみあります。
現在、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();
}
}
} ] )
これには明らかなタイマーの使用の欠点(これはい感じがします)とナビゲーションのサイズ変更後の特定の遅延がコンテンツが移動するまでです。
これを行うためのより良い方法はありますか?
これは、emHeightSource
にウォッチャーを登録することで機能します。これは、$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();
} );
}
}
} )
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とサイズ変更イベントの組み合わせを使用しました。スコープなしで見つけました。$ 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();
});
};
このアプローチは、ダイジェストサイクルごとに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
)
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は常に画像と同じ高さを(1秒の待ち時間で)保持します。
このアプローチは、要素の高さと幅を監視し、要素属性で提供されるスコープの変数に割り当てます
<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);
}
}])