33

コントローラで定義されているスコープ変数$scope.first_unread_idがあります。私のテンプレートには、次のものがあります。

<div id="items" >
  <ul class="standard-list">
    <li ng-repeat="item in items" scroll-to-id="first_unread_id">
    <span class="content">{{ item.content }}</span>
    </li>
  </ul>
</div>

私のディレクティブは次のようになります。

angular.module('ScrollToId', []).
directive('scrollToId', function () {
  return function (scope, element, attributes) {
    var id = scope.$parent[attributes["scrollToId"]];
    if (id === scope.item.id) {
      setTimeout(function () {
        window.scrollTo(0, element[0].offsetTop - 100)
      }, 20);
    }
  }

});

ただし、機能します。2つの質問があります。

  1. 「first_unread_id」をコントローラースコープから直接スコープに取り込むより良い方法はありますか。$parent?これは少し「厄介」のようです。私はそれを、これまでのli要素で繰り返す必要のないパラメーターとして、ビューを介して直接に渡すことができることを望んでいました。

  2. setTimeout()呼び出しの必要性を回避するためのより良い方法はありますか?それがないと、時々動作します-レイアウトのタイミングの違いのために想像します。私が使用した構文がリンク関数を定義していることは理解していますが、それがデフォルトでプレリンクなのかポストリンクなのか、そしてそれが私の問題にとって重要なのかどうかはわかりません。

4

7 に答える 7

39
  1. scope。$parentは必要ありません。親スコープから値を継承し、親スコープで変更されると渡されるためです。
  2. デフォルトはポストリンク機能です。最初の読み込みの直後にページレイアウトを変更する画像や読み込み中のものはありますか?setTimeout(function(){})のように、時間がない状態でsetTimeoutを試しましたか?これにより、他のすべてが行われた後、これが確実に実行されます。
  3. また、ディレクティブのロジックを少し変更して、より一般的にします。与えられた条件が真なら、要素までスクロールさせます。

これらの3つの変更は次のとおりです。

html:

<div id="items" >
  <ul class="standard-list">
    <li ng-repeat="item in items" scroll-if="item.id == first_unread_id">
      <span class="content">{{ item.content }}</span>
    </li>
  </ul>
</div>

JS:

app.directive('scrollIf', function () {
  return function (scope, element, attributes) {
    setTimeout(function () {
      if (scope.$eval(attributes.scrollIf)) {
        window.scrollTo(0, element[0].offsetTop - 100)
      }
    });
  }
});
于 2012-10-09T00:20:05.700 に答える
11

親要素がスクロールする要素であると仮定すると、これは私にとってはうまくいきます。

app.directive('scrollIf', function () {
  return function(scope, element, attrs) {
    scope.$watch(attrs.scrollIf, function(value) {
      if (value) {
        // Scroll to ad.
        var pos = $(element).position().top + $(element).parent().scrollTop();
        $(element).parent().animate({
            scrollTop : pos
        }, 1000);
      }
    });
  }
});
于 2013-12-15T09:00:58.387 に答える
6

スクロール要素がウィンドウでない場合にも機能する次のコード(jQに依存しない)になりました。

app.directive('scrollIf', function () {
    var getScrollingParent = function(element) {
        element = element.parentElement;
        while (element) {
            if (element.scrollHeight !== element.clientHeight) {
                return element;
            }
            element = element.parentElement;
        }
        return null;
    };
    return function (scope, element, attrs) {
        scope.$watch(attrs.scrollIf, function(value) {
            if (value) {
                var sp = getScrollingParent(element[0]);
                var topMargin = parseInt(attrs.scrollMarginTop) || 0;
                var bottomMargin = parseInt(attrs.scrollMarginBottom) || 0;
                var elemOffset = element[0].offsetTop;
                var elemHeight = element[0].clientHeight;

                if (elemOffset - topMargin < sp.scrollTop) {
                    sp.scrollTop = elemOffset - topMargin;
                } else if (elemOffset + elemHeight + bottomMargin > sp.scrollTop + sp.clientHeight) {
                    sp.scrollTop = elemOffset + elemHeight + bottomMargin - sp.clientHeight;
                }
            }
        });
    }
});
于 2015-02-06T15:51:34.907 に答える
3

受け入れられた回答と同じですが、javascriptの組み込みメソッド「scrollIntoView」を使用します。

angular.module('main').directive('scrollIf', function() {
    return function(scope, element, attrs) {
        scope.$watch(attrs.scrollIf, function(value) {
            if (value) {
                element[0].scrollIntoView({block: "end", behavior: "smooth"});
            }
        });
    }
});
于 2016-09-02T07:29:24.207 に答える
1

UIルーターの$uiViewScrollと組み合わせると、次のディレクティブになりました。

app.directive('scrollIf', function ($uiViewScroll) {
    return function (scope, element, attrs) {
        scope.$watch(attrs.scrollIf, function(value) {
            if (value) {
                $uiViewScroll(element);
            }
        });
    }
});
于 2015-08-21T18:02:32.593 に答える
0

@uriと組み合わせると、これは.runのui-routerとstateChangeSuccessを使用した動的コンテンツで機能します。

$rootScope.$on('$stateChangeSuccess',function(newRoute, oldRoute){

        setTimeout(function () {
            var postScroll = $state.params.postTitle;
            var element = $('#'+postScroll);
            var pos = $(element).position().top - 100 + $(element).parent().scrollTop();
            $('body').animate({
                scrollTop : pos
            }, 1000);
        }, 1000);

    });
于 2016-02-10T21:33:22.873 に答える
0

ES6のここでの答えを最大限に活用する答えについては:

ファイル:scroll.directive.js

export default function ScrollDirective() {
    return {
        restrict: 'A',
        scope: {
            uiScroll: '='
        },
        link: link
    };

    function link($scope, $element) {
        setTimeout(() => {
            if ($scope.uiScroll) {
                $element[0].scrollIntoView({block: "end", behavior: "smooth"});
            }
        });
    }
}

ファイルscroll.module.js

import ScrollDirective from './scroll.directive';

export default angular.module('app.components.scroll', [])
    .directive('uiScroll', ScrollDirective);

プロジェクトにインポートした後、HTMLで使用できます。

<div id="items" >
  <ul class="standard-list">
    <li ng-repeat="item in items" ui-scroll="true">
    <span class="content">{{ item.content }}</span>
    </li>
  </ul>
</div>
于 2017-06-26T09:42:35.117 に答える