刷新后在AngularJS中保持滚动位置 [英] Persisting scroll position in AngularJS after refresh
问题描述
我有一个用AngularJS编写的Web应用程序:
示例plunkr,这里有一些自定义: http://plnkr.co/edit/CTVgvEoY7CnLX38o70i4?p =预览
基本上,您可以设置location.hash并滚动到它.希望它对您有用,因为您的设置会稍微复杂一些.
e:刚刚注意到它实际上将视口聚焦在最后一个项目上,这实际上是不希望的.
I've got a web app I've written with AngularJS: http://asmor.com/anr
This app is for helping to build decks for a particular game.
When you add cards to your deck, they're added to a fixed-positioned div in the top right corner. That div has a dynamically-set max-height so that it won't be occluded by the bottom of the browser's window or by another fixed div in the bottom right corner of the page.
If you hit the max height, the list of cards in the deck scrolls. See below:
Now the problem is that when you add or remove a card from the deck while it's scrolled by clicking the red or green buttons, Angular redraws the deck list and resets the scroll back to the top.
For convenience, here's the code I'm using for the deck list:
<div id="deck" class="shown-{{ deck.notEmpty }} faction{{ deck.identity.faction }}">
<div class="deckStat cardTotal">
<strong class="valid-{{ deck.enoughCards }}">Cards:</strong> {{ deck.cardCount }} / {{ deck.minCards }}
</div>
<div class="deckStat agendaPointsTotal shown-{{ deck.isCorp }}">
<strong class="valid-{{ deck.enoughAgendaPoints }}">Agenda points:</strong> {{ deck.totalPoints }} / {{ deck.minPoints }}
</div>
<div class="deckStat influencePointsTotal">
<strong class="valid-{{ deck.withinInfluenceLimit }}">Influence points:</strong> {{ deck.influenceTotal }} / {{ deck.influenceAvailable }}
</div>
<div class="deckIdentity" ng-mouseover="setPreviewLink(deck.identity)">
<strong>Identity:</strong>
{{ deck.identity.name }}
</div>
<div id="deckScrollContainer" style="max-height: {{ getMaxDeckHeight() }}px">
<ul ng-repeat="(typeName, typeHash) in deck.cardsByType">
<li class="deckTypeHeader">
<strong>{{ typeName }}</strong>
<span class="quantity">
({{ typeHash.qty }})
</span>
</li>
<li ng-repeat="(cardName, qty) in typeHash.cards" class="card faction{{ getCardFaction(cardName) }}" ng-mouseover="setPreviewLink(cardName)">
<button class="btn btn-mini btn-success add qty{{qty}}" ng-click="addCard(cardName)"><i class="icon-plus"></i></button>
<button class="btn btn-mini btn-danger remove qty{{qty}}" ng-click="removeCard(cardName)"><i class="icon-minus"></i></button>
<span class="quantity">
{{ qty }}x
</span>
{{ cardName }}
<span class="influence">
{{ getInfluenceString(cardName, qty) }}
</span>
</li>
</ul>
</div>
</div>
One thing I've tried was adding a function when you add or remove cards that will grab the current scroll position, and then later on replace it.
$scope.addCard = function (c) {
$scope.setDeckScroll();
$scope.deck.add(c);
};
$scope.setDeckScroll = function () {
$scope.deckScrollPosition = document.getElementById("deckScrollContainer").scrollTop;
};
And...
$scope.getCardFaction = function (card) {
$scope._persist();
card = getCardByName(card);
return card.faction;
};
$scope._persist = function () {
// Any weird stuff that needs to be done on redraw/refresh
if ($scope.deckScrollPosition) {
document.getElementById("deckScrollContainer").scrollTop = $scope.deckScrollPosition;
$scope.deckScrollPosition = null;
}
};
As far as I can tell, Angular is redrawing the page many times when it does redraw it. I don't know when the last re-draw is going to be, and I can't just blindly set the scrollPosition every time because then if someone scrolled to the top on their own I wouldn't be able to tell the difference between that and if it had scrolled to the top because of a redraw.
One option I've considered is using a setTimeout to clear $scope.deckScrollPosition, so that
I was able to get it to work by clearing the scroll position variable with a setTimeout (so that every redraw would have access to the variable)
$scope._persist = function () {
// Any weird stuff that needs to be done on redraw/refresh
if ($scope.deckScrollPosition) {
document.getElementById("deckScrollContainer").scrollTop = $scope.deckScrollPosition;
setTimeout(function () {
$scope.deckScrollPosition = null;
}, 100);
}
};
...but this seems really hacky. I'm hoping there might be a better way. Any ideas on how I could either...
Make angular only redraw once per change in the data (e.g. maybe I've coded something poorly that's forcing it to redraw multiple times?)
Somehow cope with the redraw without resorting to setTimeout chicanery?
Found an answer here:
http://www.benlesh.com/2013/02/angular-js-scrolling-to-element-by-id.html
And the example plunkr, a little customised is here:http://plnkr.co/edit/CTVgvEoY7CnLX38o70i4?p=preview
Basically, you set the location.hash and the scroll to it. Hope it works for you, as you setup is a little more complex.
e: Just noticed that it actually focusses the viewport on the last item, which is in fact undesireable.
这篇关于刷新后在AngularJS中保持滚动位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!