bestsource

AngularJS에서 ng-repeat 스크롤 위치를 유지하는 방법은 무엇입니까?

bestsource 2023. 3. 5. 10:12
반응형

AngularJS에서 ng-repeat 스크롤 위치를 유지하는 방법은 무엇입니까?

DEMO

개체 목록은 다음을 사용하여 렌더링됩니다.ng-repeat이 목록이 매우 길어서 사용자가 아래쪽으로 스크롤하여 개체를 볼 수 있다고 가정합니다.

사용자가 개체를 관찰하는 동안 새 항목이 목록의 맨 위에 추가됩니다.이로 인해 관찰된 물체의 위치가 변경됩니다. 즉, 사용자가 관찰된 물체의 동일한 위치에서 갑자기 다른 무언가를 보게 됩니다.

새로운 아이템이 추가되었을 때 관찰된 오브젝트를 같은 장소에 보관하는 방법은 무엇입니까?

PLAYGROUND HERE

어쩌면 꽤 우아하게 해결되었을지도 몰라scrollTop의 of의 div두 가지 지시어를 사용했습니다. 하나는 래퍼 요소의 스크롤 위치를 다루고 다른 하나는 새로운 요소를 등록합니다.★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

데모

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

HTML:

<div class="wrapper" keep-scroll>
  <div class="item" scroll-item ng-repeat="item in items  | orderBy: '-id'">
    {{ item.name }}
   </div>
</div>

다른 사람들은 UI와 관련하여 다른 접근 방식을 사용하여 이 문제를 해결하려고 합니다.새 항목이 위에 팝업될 뿐만 아니라 맨 위에 클릭 가능한 작은 링크가 표시되어 그가 마지막으로 항목을 확인한 이후 추가된 새 항목의 수를 나타냅니다.

[2 new items, Click here to refresh]

item 5
item 4
item 3

이 문제를 . ** [잠시 후 스크린샷을 첨부합니다]

당신이 원하는 것과 조금 모순된다는 것을 알지만, UX라는 측면에서 이것이 더 낫지 않을까요?사용자는 새로운 아이템이 들어오는지 알고 싶어 합니다.

추가된 요소의 높이만큼 스크롤할 수 있습니다.

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

컨트롤러에서 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);
  };

http://jsbin.com/zofofapo/9/edit에서 데모를 하다

아래는 추가된 항목이 스크롤 위 또는 아래에 추가되었는지 여부에 관계없이 스크롤을 방지하는 Arthur 버전의 개선 사항입니다.

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

사용자가 목록의 맨 위를 스크롤하여 보기로 이동할 때까지 항목 추가를 연기할 수 있습니다.이전에 아이템을 렌더링하는 것은 의미가 없습니다.

이렇게 보일 수 있습니다(애니메이션이 추가되었을 수도 있습니다.

Facebook의 방법: 모두가 이것을 제안하고 있습니다.여기에는 유사 구현이 있습니다.

새 개체가 추가되면 "More Queue(추가 대기열)"에 해당 개체를 팝합니다.

  <div style="height:15px">
      <button  ng-if="moreQueue"ng-click="transferWait()"> See More {{ moreQueue }}
      </button >
    </div>  
  <div class="wrapper">
    <div class="item" ng-repeat="item in items | orderBy: '-id'">
      {{ item.name }}
    </div>
  </div>

MessageHandlerController에는 적어도2개의 어레이가 있습니다(큐의 b/c로 취급합니다).아래에서 위로 팝업이 표시됩니다.

  • 액티브 메시지
  • 대기 메시지

Signal R/Service Bus가 입력되면WaitingQueue,당신의.ng-if사이즈가 증가하여$scope.SizeOfWaitingQueue=SizeOfWaitingQueue()이 재할당 프로세스는 반복할 때마다 진행되므로 큰 크기의 Repo를 더티 체크할 필요가 없습니다.

모든 사용자 스크롤에서 위치를 업데이트하고 반복 렌더링할 때마다 알림을 받는 스크롤 스파이 지시문을 컨테이너에 추가해야 저장된 상태로 스스로 재배치할 수 있습니다.html은 이렇게 보일 수 있습니다.

<div scrollspy id="myscrollspy">
     <ul>
       <li ng-repeat="" notifyscroll></li>
     </ul>
</div>

스크롤 스파이에는 현재 스크롤을 추적하기 위해 필요한 css 오버플로 설정 및 스크롤-x 또는 스크롤-y가 있으며 변경 발생 및 스크루 설정을 통지하는 ng-drives로부터의 이벤트도 감시할 필요가 있습니다.

ng-timeout은 이벤트를 시작하는 새로운 디렉티브 알림 스크롤을 첨부하여 알릴 수 있습니다.angular의 curretn 버전이 postrender 이벤트를 지원하는지 확실하지 않습니다.

스크롤을 배치하는 방법은 서드파티 라이브러리 $.scrollTop(pos)을 사용하는지 여부에 따라 달라집니다.이것으로 충분할지 어떨지는 결정됩니다.도움이 되었으면 좋겠다

제 생각에, 몇 가지 가능한 해결책이 있습니다.

1) 아이템 추가 안 함 (다른 답변과 동일)

2) 리스트가 이동하지 않도록 하단에 아이템을 추가합니다.

3) 아이템을 맨 위에 추가하여 자동으로 화면을 스크롤하여 새로운 아이템의 높이를 파악하여 모든 것을 이전과 같이 유지합니다.리스트는 아래로 이동하지만, 표시 가능한 화면 자체는 이동하기 때문에 상대적으로 아무것도 이동하지 않습니다.목록에 포함되지 않은 다른 요소들도 있겠지만, 실제로 꽤 좋아 보일 수 있습니다.

이 문제는 ng-animate로 해결할 수 있습니다.

.animation('.keep-scroll', [function () {
    var keepScroll = function(element, leave){
        var elementPos = element.offset().top;
        var scrollPos = document.body.scrollTop;

        if(elementPos < scrollPos){
            var height = element[0].clientHeight;
            if(leave){
                height *= (-1);
            }
            document.body.scrollTop += height;
        }
    };

    return {
        enter: function (element, doneFn) {
            keepScroll(element);
            doneFn();
        },
        leave: function (element, doneFn) {
            keepScroll(element, true);
            doneFn();
        }
    };
}])

다음과 같이 반복 요소에 css-class.keep-scroll을 할당합니다.

<div ng-repeat="item in items" class="keep-scroll">...</div>

언급URL : https://stackoverflow.com/questions/23736647/how-to-retain-scroll-position-of-ng-repeat-in-angularjs

반응형