我認爲最初的解決方案是一種哈克內事件中......但這是一個使用它作爲基礎的工作編輯。
問題是解決方案取決於添加到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>
這是最好的解決方案。非常完整,遵循良好的角度做法。正如你所提到的,這兩種解決方案都是如果它滾動到底部並且點擊刪除項目按鈕,滾動會跳到某個任意位置。那會是什麼原因? –