fix: StatsSummary 增量更新时只动画变化的列,不再全部重播
首次加载仍全部 count-up。后续 items 变化时对比新旧值, 只对值发生变化的列触发动画,其他列保持静止。 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
7c1e0a4e18
commit
847f3a52ea
@ -22,15 +22,29 @@ export default {
|
||||
items: { type: Array, default: () => [] },
|
||||
},
|
||||
data() {
|
||||
return { displayValues: [], _animated: false, _observer: null };
|
||||
return { displayValues: [], _animated: false, _observer: null, _prevItems: null };
|
||||
},
|
||||
watch: {
|
||||
items: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
this.displayValues = this.items.map((v) => v.value);
|
||||
this._animated = false;
|
||||
this.$nextTick(() => this._observe());
|
||||
handler(cur, old) {
|
||||
if (!old || !this._prevItems) {
|
||||
// 首次加载:全部初始化
|
||||
this.displayValues = cur.map((v) => v.value);
|
||||
this._animated = false;
|
||||
this._prevItems = cur.map((v) => v.value);
|
||||
this.$nextTick(() => this._observe());
|
||||
return;
|
||||
}
|
||||
// 增量更新:只动画变化的值
|
||||
const prev = this._prevItems;
|
||||
cur.forEach((item, idx) => {
|
||||
if (String(item.value) !== String(prev[idx])) {
|
||||
// 值变了,触发该位置的动画
|
||||
this._animateOne(idx, Number(item.value));
|
||||
}
|
||||
});
|
||||
this._prevItems = cur.map((v) => v.value);
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -57,6 +71,25 @@ export default {
|
||||
}, { threshold: 0.2 });
|
||||
this._observer.observe(root);
|
||||
},
|
||||
_animateOne(idx, target) {
|
||||
if (Number.isNaN(target)) {
|
||||
this.$set(this.displayValues, idx, target);
|
||||
return;
|
||||
}
|
||||
const startVal = Number(this.displayValues[idx]) || 0;
|
||||
const diff = target - startVal;
|
||||
if (diff === 0) return;
|
||||
const start = performance.now();
|
||||
const duration = Math.min(600 + Math.abs(diff) * 3, 1200);
|
||||
const tick = (now) => {
|
||||
const p = Math.min((now - start) / duration, 1);
|
||||
const eased = 1 - Math.pow(1 - p, 3);
|
||||
const current = Math.round(startVal + eased * diff);
|
||||
this.$set(this.displayValues, idx, current.toLocaleString());
|
||||
if (p < 1) requestAnimationFrame(tick);
|
||||
};
|
||||
requestAnimationFrame(tick);
|
||||
},
|
||||
_animateAll() {
|
||||
if (this._animated) return;
|
||||
this._animated = true;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user