LoginSignup
9

More than 5 years have passed since last update.

[AngularJS] コレクションに挿入した後にスクロール位置を保持する

Last updated at Posted at 2015-10-23

やりたいこと

コレクションをng-repeatで描画しているときに、そのコレクションに対してunshift(先頭に挿入)した場合、DOM描画後にスクロール位置が先頭に移動してしまいます。これを回避したいという話です。

解決方法

厳密に言うと、「元のスクロール位置を保持」しているからこそ、先頭に移動してしまうわけで。。。つまり、もともとスクロール位置が画面トップだった場合はscrollTop == 0ですが、unshiftによる再描画後もscrollTop == 0のままなので、スクロール位置が先頭に来ているというわけです。

というわけで、再描画後にスクロールコンテナの高さが増えた分だけ下にスクロールさせてやればよい、ということになります。(ベストな方法かは分からないですが・・・)

サンプル

初期状態ではitemsというコレクションを100件表示します。画面上部の"Load Previous Items"というリンクをクリックすれば、その前にさらに100件のitemを読み込みます。その際にスクロール位置を保持するというサンプルです。

index.html
<!doctype html>
<html ng-app="app">
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
    <script src="app.js"></script>
  </head>
  <body ng-controller="ItemsCtrl" keep-scroll-position>
    <a href="" ng-click="loadPreviousItems()" ng-if="!loaded">Load Previous Items</a>
    <div ng-repeat="item in items">
      <div>{{item}}</div>
    </div>
  </body>
</html>
app.js
angular.module('app', [])

.controller('ItemsCtrl', function($scope) {
  $scope.items = [];

  for (var i=100; i < 200; i++) {
    $scope.items.push('item' + i);
  }

  $scope.loadPreviousItems = function() {
    var previousItems = [];
    for (var i=0; i < 100; i++) {
      previousItems.push('item' + i);
    }
    Array.prototype.unshift.apply($scope.items, previousItems);
    $scope.loaded = true;
  };
})

.directive('keepScrollPosition', function() {
  return function(scope, el, attrs) {
    scope.$watch(
      function() { return el[0].clientHeight; },
      function(newHeight, oldHeight) {
        console.debug('Height was changed', oldHeight, newHeight);
        el[0].scrollTop = newHeight - oldHeight;
      });
  };
});

jsFiddleはこちら

ソース解説

keepScrollPositionというディレクティブにスクロールコンテナ(この場合はbody)の高さを監視してます。高さに変更があったら(=itemsが追加された)スクロール位置を元の場所まで移動してやります。

_

できてみると、めちゃくちゃ単純なコードなんですが、「高さを監視する」という発想に至るまでかなり時間を要してしまいました・・・。

参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9