如何在AngularJS中保留ng-repeat的滚动位置?

Mis*_*hko 30 scroll angularjs angularjs-ng-repeat

DEMO

使用的对象列表ng-repeat.假设此列表非常长并且用户滚动到底部以查看某些对象.

当用户观察对象时,新项目将添加到列表顶部.这导致观察对象改变其位置,即用户突然在观察对象的相同位置看到其他东西.

当添加新项目时,您将如何将观察对象保持在同一位置?

PLAYGROUND HERE

art*_*iak 30

通过使用scrollTop属性,它可以很优雅地解决div.我使用了两个指令 - 一个处理包装元素的滚动位置,另一个指定新元素.如果有什么不清楚的话,请给我一个喊叫.

DEMO

JS:

.directive("keepScroll", function(){

  return {

    controller : function($scope){
      var element = null;

      this.setElement = function(el){
        element = el;
      }

      this.addItem = function(item){
        console.log("Adding item", item, item.clientHeight);
        element.scrollTop = (element.scrollTop+item.clientHeight+1);
       //1px for margin from your css (surely it would be possible
       // to make it more generic, rather then hard-coding the value)
      };

    },

    link : function(scope,el,attr, ctrl) {

     ctrl.setElement(el[0]);

    }

  };

})

.directive("scrollItem", function(){

  return{
    require : "^keepScroll",
    link : function(scope, el, att, scrCtrl){
      scrCtrl.addItem(el[0]);
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

HTML:

<div class="wrapper" keep-scroll>
  <div class="item" scroll-item ng-repeat="item in items  | orderBy: '-id'">
    {{ item.name }}
   </div>
</div>
Run Code Online (Sandbox Code Playgroud)


fed*_*ich 7

您知道其他人正在尝试使用不同的UI方法解决此问题.它们不只是在顶部突出显示新项目,而是在顶部显示一个小的可点击链接,说明自上次检查后添加了多少新项目.

[2 new items, Click here to refresh]

item 5
item 4
item 3
Run Code Online (Sandbox Code Playgroud)

看看twitter如何解决这个问题. **[让我稍后为您附上截图.]**

我知道这与你想要的东西有点矛盾,但也许这在UX方面更好?用户想知道是否有新物品进入.


Gab*_*oli 5

您可以滚动添加元素的高度

$scope.addNewItem = function() {
    var wrapper = document.getElementsByClassName('wrapper')[0];

    $scope.items = $scope.items.concat({
      id: $scope.items.length,
      name: "item " + $scope.items.length
    });
    // will fail if you observe the item 0 because we scroll before the view is updated;
    wrapper.scrollTop+=101; //height+margings+paddings
  };
Run Code Online (Sandbox Code Playgroud)

我正在使用从控制器访问DOM的错误做法.更模块化的方法是创建一个指令,它将处理所有情况并在更新视图后更改滚动位置.

演示http://jsbin.com/zofofapo/8/edit


或者,对于项目不是同样高的情况,您可以看到插入前剩余多少滚动,并在插入后重新设置

$scope.addNewItem = function() {
    var wrapper = document.getElementsByClassName('wrapper')[0],
        scrollRemaining = wrapper.scrollHeight - wrapper.scrollTop;

    $scope.items = $scope.items.concat({
      id: $scope.items.length,
      name: "item " + $scope.items.length
    });
    // will fail if you observe the item 0 because we scroll before the view is updated;
    $timeout(function(){
      wrapper.scrollTop = wrapper.scrollHeight - scrollRemaining;
    },0);
  };
Run Code Online (Sandbox Code Playgroud)

演示http://jsbin.com/zofofapo/9/edit


Vit*_*lyB 5

以下是对 Arthur 版本的改进,无论添加的项目是在滚动上方还是下方添加,都可以防止滚动: JS Bin

angular.module("Demo", [])

.controller("DemoCtrl", function($scope) {
  $scope.items = [];
  
  for (var i = 0; i < 10; i++) {
    $scope.items[i] = {
      id: i,
      name: 'item ' + i
    };
  }
  
  $scope.addNewItemTop = function() {
    $scope.items.unshift({
      id: $scope.items.length,
      name: "item " + $scope.items.length
    });
  };
  
  $scope.addNewItemMiddle = function() {
    $scope.items.splice(5, 0, {
      id: $scope.items.length,
      name: "item " + $scope.items.length
    });
  };
  
  $scope.addNewItemBottom = function() {
    $scope.items = $scope.items.concat({
      id: $scope.items.length,
      name: "item " + $scope.items.length
    });
  };
})

.directive("keepScroll", function(){
  
  return {

    controller : function($scope){
      var element = 0;
      
      this.setElement = function(el){
        element = el;
      };

      this.addItem = function(item){
        console.group("Item");
        console.log("OffsetTop: " + item.offsetTop);
        console.log("ScrollTop: " + element.scrollTop);
        
        if(item.offsetTop <= element.scrollTop) {
          console.log("Adjusting scorlltop position");
          element.scrollTop = (element.scrollTop+item.clientHeight+1); //1px for margin
        } else {
          console.log("Not adjusting scroll");
        }
        console.groupEnd("Item");
      };
      
    },
    
    link : function(scope,el,attr, ctrl) {
      
     ctrl.setElement(el[0]);
      
    }
    
  };
  
})

.directive("scrollItem", function(){
  
  
  return{
    require : "^keepScroll",
    link : function(scope, el, att, scrCtrl){
      scrCtrl.addItem(el[0]);
    }
  };
});
Run Code Online (Sandbox Code Playgroud)
.wrapper {
  width: 200px;
  height: 300px;
  border: 1px solid black;
  overflow: auto;
  /* Required for correct offsetParent */
  position: relative; 
}
.item {
  background-color: #ccc;
  height: 100px;
  margin-bottom: 1px;
}
Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>
<head>
<script src="//code.angularjs.org/1.3.0-beta.7/angular.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body ng-app="Demo" ng-controller="DemoCtrl">
  <div class="wrapper" keep-scroll>
    <div class="item" scroll-item ng-repeat="item in items">
      {{ item.name }}
    </div>
  </div>
  <button ng-click="addNewItemTop()">
    Add New Item Top
  </button>
  <button ng-click="addNewItemMiddle()">
    Add New Item Middle
  </button>
  <button ng-click="addNewItemBottom()">
    Add New Item Bottom
  </button>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)