从顶部删除项目时,如何在AngularJS中保留ng-repeat的滚动位置

时间:2015-11-15 19:30:26

标签: angularjs scroll angularjs-ng-repeat

我尝试从解决方案到这个

How to retain scroll position of ng-repeat in AngularJS?

在删除ng-repeat中的顶部项目时保持滚动位置,但无法确定代码。

另外,请注意,列表应按与items数组相同的顺序打印,而不是与示例相反。

解决方案的代码:

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.addNewItem = 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.log("Adding item", item, item.clientHeight);
        element.scrollTop = (element.scrollTop+item.clientHeight+1); //1px for margin
      };

    },

    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]);
    }
  }
})

我尝试做的是改变

element.scrollTop = (element.scrollTop + item.clientHeight+1)

element.scrollTop = (element.scrollTop - item.clientHeight+1)

按顺序打印&#39; id&#39;不是&#39; -id&#39;

3 个答案:

答案 0 :(得分:5)

我认为最初的解决方案有点像hacky ......但这是一个使用它作为基础的工作编辑。

问题在于解决方案取决于添加到ng-repeat的项目。如果查看scrollItem指令,它只会导致keepScroll指令在链接器执行时重新调整scrollTop。只有在添加项目而不是删除项目时才会发生这种情况。

编辑会侦听scope.$on('$destroy')事件。但是,此时的问题是该元素不再具有clientHeight,因为它已从DOM中删除。因此,解决方案是在创建时保存其高度,然后告诉keepScroll删除元素的高度是什么。

注意:如果滚动条一直到底部,这似乎会导致滚动跳转,因此您需要将该情况视为异常。

使用JSBin:http://jsbin.com/geyapugezu/1/edit?html,css,js,output

供参考:

<强> HTML

<!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 | orderBy: 'id'">
      {{ item.name }}
    </div>
  </div>
  <button ng-click="removeItem()">
    Remove item
  </button>
</body>
</html>

<强> CSS

.wrapper {
  width: 200px;
  height: 300px;
  border: 1px solid black;
  overflow: auto;
}
.item {
  background-color: #ccc;
  height: 100px;
  margin-bottom: 1px;
}

<强> JS

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.removeItem = function() {
      $scope.items = $scope.items.slice(1);
    };
})
.directive("keepScroll", function(){

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

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

      this.itemRemoved = function(height){
        element.scrollTop = (element.scrollTop - height - 1); //1px for margin
        console.log("Item removed", element.scrollTop);
      };

    },

    link : function(scope,el,attr, ctrl) {
     ctrl.setElement(el[0]);

    }

  };

})
.directive("scrollItem", function(){


  return {
    require : "^keepScroll",
    link : function(scope, el, att, scrCtrl){
      var height = el[0].clientHeight;

      scope.$on('$destroy', function() {
        scrCtrl.itemRemoved(height);
      });
    }
  };
});

修改

或者,这样做。不需要scrollItem,而是我们观察ng-repeat项目的更改并相应地重新调整scrollTop。

JSBin:http://jsbin.com/dibeqivubi/edit?html,css,js,output

<强> JS

angular.module("Demo", [])
  .controller("DemoCtrl", ['$scope', function($scope) {
    $scope.items = [];

    for (var i = 0; i < 10; i++) {
      $scope.items[i] = {
        id: i,
        name: 'item ' + i
      };
    }

    $scope.removeItem = function() {
      $scope.items = $scope.items.slice(1);
    };
}])
.directive("keepScroll", function() {
  return {
    link : function(scope,el,attr, ctrl) {
      var scrollHeight;

      scope.$watchCollection('items', function(n,o) {
        // Instantiate scrollHeight when the list is
        // done loading.
        scrollHeight = scrollHeight || el[0].scrollHeight;
        // Adjust scrollTop if scrollHeight has changed (items
        // have been removed)
        el[0].scrollTop = el[0].scrollTop - (scrollHeight - el[0].scrollHeight);
        // Remember current scrollHeight for next change.
        scrollHeight = el[0].scrollHeight;
      });
    }

  };
});

<强> HTML

<!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" ng-repeat="item in items | orderBy: 'id'">
      {{ item.name }}
    </div>
  </div>
  <button ng-click="removeItem()">
    Remove item
  </button>
</body>
</html>

答案 1 :(得分:0)

我希望$anchorScroll可以帮到你。关注link

答案 2 :(得分:0)

我不确定我是否理解正确,但您可以通过收听要删除的items数组和项目来实现您想要的效果。

希望这会有所帮助

http://plnkr.co/edit/buGcRlVGClj6toCVXFKu?p=info

这就是我的所作所为:

为商品

添加了高度属性
for (var i = 0; i < 20; i++) {
    $scope.items[i] = {
        id: i,
        name: 'item ' + i,
        height: (Math.random()*100)+30
    };
}
html文件中的

style: height属性

<div class="wrapper" keep-scroll>
    <div class="item" scroll-item ng-repeat="item in items" style="height:{{item.height}}px">
        {{ item.name }}
    </div>
</div>
DemoCtrl中的

deleteItem方法

$scope.deleteItem = function() {
    var itemToDelete = $scope.items[0];
    $scope.items.splice(0,1);
    $scope.$broadcast("scrollFix",itemToDelete);
};

比我在 keepScroll 指令中听 scrollFix 事件

$scope.$on('scrollFix',function(event,data){
   element.scrollTop = element.scrollTop - data.height;
});