从顶部删除项目时如何在AngularJS中保留ng-repeat的滚动位置 [英] How to retain the scroll position of ng-repeat in AngularJS when removing an item from the top

查看:16
本文介绍了从顶部删除项目时如何在AngularJS中保留ng-repeat的滚动位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图解决这个问题

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

在ng-repeat中删除顶部项目时实现保留滚动位置,但无法弄清楚这样做的代码.

另外,附注,列表应该以与 items 数组相同的顺序打印,而不是像示例那样相反.

解决方案的代码:

angular.module("Demo", []).controller("DemoCtrl", function($scope) {$scope.items = [];for (var i = 0; i <10; i++) {$scope.items[i] = {身份证:我,名称:'项目' + i};}$scope.addNewItem = function() {$scope.items = $scope.items.concat({id: $scope.items.length,名称:项目"+ $scope.items.length});};}).directive("keepScroll", function(){返回 {控制器:功能($范围){var 元素 = 0;this.setElement = function(el){元素 = el;}this.addItem = 函数(项目){console.log("添加项目", item, item.clientHeight);element.scrollTop = (element.scrollTop+item.clientHeight+1);//1px 为边距};},链接:函数(范围,el,attr,ctrl){ctrl.setElement(el[0]);}};}).directive("scrollItem", function(){返回{要求:^keepScroll",链接:函数(范围,el,att,scrCtrl){scrCtrl.addItem(el[0]);}}})

我尝试做的是改变

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

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

并按id"而不是-id"按顺序打印

解决方案

我认为最初的解决方案有点笨拙......但这里有一个使用它作为基础的工作编辑.

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

编辑改为监听 scope.$on('$destroy') 事件.然而,此时的问题是,该元素不再具有 clientHeight,因为它已从 DOM 中删除.所以解决方案是在创建时保存它的高度,然后告诉keepScroll移除元素的高度是多少.

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

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

供参考:

HTML

<头><script src="//code.angularjs.org/1.3.0-beta.7/angular.js"></script><meta charset="utf-8"><title>JS Bin</title><body ng-app="Demo" ng-controller="DemoCtrl"><div class="wrapper" keep-scroll><div class="item" scroll-item ng-repeat="item in items | orderBy: 'id'">{{ 项目名称 }}

<button ng-click="removeItem()">除去项目</html>

CSS

.wrapper {宽度:200px;高度:300px;边框:1px纯黑色;溢出:自动;}.物品 {背景颜色:#ccc;高度:100px;底边距:1px;}

JS

angular.module("Demo", []).controller("DemoCtrl", function($scope) {$scope.items = [];for (var i = 0; i <10; i++) {$scope.items[i] = {身份证:我,名称:'项目' + i};}$scope.removeItem = function() {$scope.items = $scope.items.slice(1);};}).directive("keepScroll", function(){返回 {控制器:功能($范围){var 元素 = 0;this.setElement = function(el){元素 = el;};this.itemRemoved = 函数(高度){element.scrollTop = (element.scrollTop - 高度 - 1);//1px 为边距console.log("物品已移除", element.scrollTop);};},链接:函数(范围,el,attr,ctrl){ctrl.setElement(el[0]);}};}).directive("scrollItem", function(){返回 {要求:^keepScroll",链接:函数(范围,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,输出

JS

angular.module("Demo", []).controller("DemoCtrl", ['$scope', function($scope) {$scope.items = [];for (var i = 0; i <10; i++) {$scope.items[i] = {身份证:我,名称:'项目' + i};}$scope.removeItem = function() {$scope.items = $scope.items.slice(1);};}]).directive("keepScroll", function() {返回 {链接:函数(范围,el,attr,ctrl){变量滚动高度;scope.$watchCollection('items', function(n,o) {//当列表为//加载完成.滚动高度 = 滚动高度 ||el[0].scrollHeight;//如果 scrollHeight 已更改,则调整 scrollTop(项目//已被删除)el[0].scrollTop = el[0].scrollTop - (scrollHeight - el[0].scrollHeight);//记住当前滚动高度以备下次更改.scrollHeight = el[0].scrollHeight;});}};});

HTML

<头><script src="//code.angularjs.org/1.3.0-beta.7/angular.js"></script><meta charset="utf-8"><title>JS Bin</title><body ng-app="Demo" ng-controller="DemoCtrl"><div class="wrapper" keep-scroll><div class="item" ng-repeat="item in items | orderBy: 'id'">{{ 项目名称 }}

<button ng-click="removeItem()">除去项目</html>

I tried to work from the solution to this

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

to achieve retaining the scroll position when removing the top item in an ng-repeat but couldn't figure out the code to do so.

Also, side note, the list should print in the same order as the items array, not in the reverse as the example does.

The solution's code:

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

What I tried doing was changing

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

to

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

and printing in order by 'id' not '-id'

解决方案

I think the initial solution is kind of hacky... but here's a working edit using it as the basis.

The problem is that the solution depends on items being added to the ng-repeat. If you look at the scrollItem directive, it only causes the keepScroll directive to readjust scrollTop if the linker gets executed. This only happens when items get added, not removed.

The edit instead listens to the scope.$on('$destroy') event. The issue at that point is however, that the element no longer has a clientHeight because it has been removed from the DOM. So the solution is to save its height when it gets created, and then instead tell keepScroll what the height of the removed element was.

Note: This seemed to cause a scroll jump if the scroller was all the way to the bottom, so you'd need to look into that case as an exception.

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

For reference:

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

EDIT

Or, do this. No need for scrollItem, instead we watch changes to the ng-repeat items and readjust the scrollTop accordingly.

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>

这篇关于从顶部删除项目时如何在AngularJS中保留ng-repeat的滚动位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆