使用ng-repeat
呈现对象列表。假设此列表非常长,用户滚动到底部以查看某些对象。
当用户观察对象时,新项目将添加到列表顶部。这会导致观察对象改变其位置,即用户突然在观察对象的同一位置看到其他东西。
如果添加新项目,您将如何将观察对象保持在同一位置?
答案 0 :(得分:30)
使用scrollTop
的{{1}}属性可以非常优雅地解决它。我使用了两个指令 - 一个处理包装元素的滚动位置,另一个指定新元素。
如果有什么不清楚的话,请给我一个喊叫。
JS:
div
HTML:
.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]);
}
}
})
答案 1 :(得分:7)
您知道其他人正在尝试使用不同的UI方法解决此问题。 它们不只是在顶部展示新项目,而是在顶部显示一个小的可点击链接,说明自上次检查后添加了多少新项目。
[2 new items, Click here to refresh]
item 5
item 4
item 3
查看Twitter如何解决这个问题。
我知道这与你想要的东西有点矛盾,但也许这在用户体验方面更好? 用户想知道是否有新物品进入。
答案 2 :(得分: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
};
我正在使用从控制器访问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);
};
演示
答案 3 :(得分:4)
以下是对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]);
}
};
});
.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>
答案 4 :(得分:3)
您可以推迟添加项目,直到用户将列表顶部滚动到视图中。以前没有必要渲染这些项目。
It could look like this(可能附加动画)。
答案 5 :(得分:2)
FaceBook方式:每个人都在暗示这一点,这是一个伪实现:
添加新对象后,将其弹出为“更多队列&#34;。
” <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个数组(我们应该将其视为队列&#39; s b / c我们将从底部向上弹出。
当您的 信号R /服务总线 填充WaitingQueue
时,您的ng-if
呈现的尺寸会增加$scope.SizeOfWaitingQueue=SizeOfWaitingQueue()
。这种重新分配过程应该在每次迭代时进行,因此您不必脏检查 更多 大小的回购
答案 6 :(得分:1)
您需要向容器添加一个scrollspy指令,以更新其在每个用户滚动上的位置,并在每次重复渲染时收到通知,以便它可以将其自身重新定位到其保存状态。你的HTML可能看起来像这样
<div scrollspy id="myscrollspy">
<ul>
<li ng-repeat="" notifyscroll></li>
</ul>
</div>
滚动间谍将具有所需的css溢出设置和scroll-x或scroll-y以跟踪当前滚动并避免污染范围它还应该观察来自ng-repeat的事件告诉他发生了变化,应该设置scrool。
ng-repeat可以通过附加启动事件的新指令通知滚动来通知。不确定currenttn版本的角度是否支持postrender事件。
定位滚动的方式取决于您是使用第三方库$ .scrollTop(pos)还是否。这样做或应该。 希望它有所帮助
答案 7 :(得分:0)
我相信,只有一些可能的解决方案
1)不要添加项目(按照其他答案)
2)在底部添加项目,因此列表不会移动。
3)在顶部和scroll the screen automatically添加项目,以便考虑新项目的高度,并且所有内容看起来都像以前一样。该列表将向下移动,但可视屏幕本身也将移动 - 因此相对来说没有任何东西可以移动。那些不属于列表的其他元素会,但实际上可能看起来很不错......
答案 8 :(得分:0)
您可以使用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>