AngularJS で作成した Web アプリがあります: http://asmor.com/anr
このアプリは、特定のゲームのデッキ構築を支援するためのものです。
カードをデッキに追加すると、それらは右上隅の固定位置の div に追加されます。その div には動的に設定された max-height があるため、ブラウザのウィンドウの下部や、ページの右下隅にある別の固定 div によって遮られることはありません。
最大の高さに達すると、デッキ内のカードのリストがスクロールします。下記参照:
ここでの問題は、赤または緑のボタンをクリックしてスクロールしているときにデッキにカードを追加または削除すると、Angular がデッキ リストを再描画し、スクロールを一番上にリセットすることです。
便宜上、デッキリストに使用しているコードは次のとおりです。
<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>
私が試したことの 1 つは、現在のスクロール位置を取得し、後でそれを置き換えるカードを追加または削除するときに関数を追加することでした。
$scope.addCard = function (c) {
$scope.setDeckScroll();
$scope.deck.add(c);
};
$scope.setDeckScroll = function () {
$scope.deckScrollPosition = document.getElementById("deckScrollContainer").scrollTop;
};
と...
$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;
}
};
私が知る限り、Angular はページを再描画するときに何度も再描画しています。最後の再描画がいつになるかはわかりません。また、毎回やみくもに scrollPosition を設定することはできません。それと、再描画のために一番上までスクロールした場合。
私が検討したオプションの 1 つは、setTimeout を使用して $scope.deckScrollPosition をクリアすることです。
setTimeout を使用してスクロール位置変数をクリアすることで、機能させることができました(すべての再描画が変数にアクセスできるようにするため)
$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);
}
};
...しかし、これは本当にハッキーに思えます。もっと良い方法があるかもしれないと思っています。どのように私ができるかについてのアイデア...
angular をデータの変更ごとに 1 回だけ再描画するようにします (たとえば、複数回再描画を強制するコードが不十分である可能性がありますか?)
setTimeout というごまかしに頼らずに、どうにかして再描画に対処できますか?