fix(input): /菜单上下键滚动抖动与高亮条偶发闪烁
- 修复 rAF 第一帧 now 早于 startTime 导致 scrollTop 反向抖动 - 过滤动画结束后的延迟 scroll 事件,避免误进入 manualScrolled 模式导致高亮条闪一下消失
This commit is contained in:
parent
2766a8ab57
commit
2c6d208be7
@ -597,6 +597,11 @@ const slashHighlightTop = ref(4);
|
|||||||
/** 手动滚动后切到鼠标 hover 模式,隐藏 JS 高亮条 */
|
/** 手动滚动后切到鼠标 hover 模式,隐藏 JS 高亮条 */
|
||||||
const slashManualScrolled = ref(false);
|
const slashManualScrolled = ref(false);
|
||||||
let slashAnimId: number | null = null;
|
let slashAnimId: number | null = null;
|
||||||
|
/** 动画真正进行中(比 animId 更可靠,可覆盖 rAF 结束后的延迟 scroll 事件) */
|
||||||
|
let slashAnimating = false;
|
||||||
|
/** 记录最近一次动画的目标 scrollTop 和结束时间,用于过滤动画后的延迟 scroll 事件 */
|
||||||
|
let lastSlashAnimatedScroll: number | null = null;
|
||||||
|
let lastSlashAnimationEndTime = 0;
|
||||||
|
|
||||||
const slashHighlightStyle = computed(() => {
|
const slashHighlightStyle = computed(() => {
|
||||||
if (slashManualScrolled.value) return { display: 'none' };
|
if (slashManualScrolled.value) return { display: 'none' };
|
||||||
@ -615,6 +620,8 @@ const animateSlash = (element: HTMLElement, targetScroll: number) => {
|
|||||||
if (interrupted) {
|
if (interrupted) {
|
||||||
cancelAnimationFrame(slashAnimId);
|
cancelAnimationFrame(slashAnimId);
|
||||||
}
|
}
|
||||||
|
slashAnimating = true;
|
||||||
|
lastSlashAnimatedScroll = targetScroll;
|
||||||
const startScroll = element.scrollTop;
|
const startScroll = element.scrollTop;
|
||||||
const startHighlight = slashHighlightTop.value;
|
const startHighlight = slashHighlightTop.value;
|
||||||
const distScroll = targetScroll - startScroll;
|
const distScroll = targetScroll - startScroll;
|
||||||
@ -624,7 +631,8 @@ const animateSlash = (element: HTMLElement, targetScroll: number) => {
|
|||||||
const startTime = performance.now();
|
const startTime = performance.now();
|
||||||
|
|
||||||
const step = (now: number) => {
|
const step = (now: number) => {
|
||||||
const elapsed = now - startTime;
|
// rAF 第一帧的 now 偶尔会早于 startTime,导致 progress 为负、scrollTop 反向抖动
|
||||||
|
const elapsed = Math.max(0, now - startTime);
|
||||||
const progress = Math.min(elapsed / duration, 1);
|
const progress = Math.min(elapsed / duration, 1);
|
||||||
const eased = 1 - Math.pow(1 - progress, 3);
|
const eased = 1 - Math.pow(1 - progress, 3);
|
||||||
element.scrollTop = startScroll + distScroll * eased;
|
element.scrollTop = startScroll + distScroll * eased;
|
||||||
@ -633,6 +641,8 @@ const animateSlash = (element: HTMLElement, targetScroll: number) => {
|
|||||||
slashAnimId = requestAnimationFrame(step);
|
slashAnimId = requestAnimationFrame(step);
|
||||||
} else {
|
} else {
|
||||||
slashAnimId = null;
|
slashAnimId = null;
|
||||||
|
slashAnimating = false;
|
||||||
|
lastSlashAnimationEndTime = performance.now();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
slashAnimId = requestAnimationFrame(step);
|
slashAnimId = requestAnimationFrame(step);
|
||||||
@ -640,7 +650,18 @@ const animateSlash = (element: HTMLElement, targetScroll: number) => {
|
|||||||
|
|
||||||
/** 手动滚动时切到鼠标 hover 模式,不再跟踪键盘选中 */
|
/** 手动滚动时切到鼠标 hover 模式,不再跟踪键盘选中 */
|
||||||
const onSlashScroll = () => {
|
const onSlashScroll = () => {
|
||||||
if (slashAnimId !== null) return;
|
if (slashAnimating || slashAnimId !== null) return;
|
||||||
|
const list = skillSlashList.value;
|
||||||
|
if (!list) return;
|
||||||
|
const now = performance.now();
|
||||||
|
// 动画结束后的延迟 scroll 事件:scrollTop 与动画目标一致,说明是动画尾声,忽略
|
||||||
|
if (
|
||||||
|
lastSlashAnimatedScroll !== null &&
|
||||||
|
now - lastSlashAnimationEndTime < 150 &&
|
||||||
|
Math.abs(list.scrollTop - lastSlashAnimatedScroll) < 1
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
slashManualScrolled.value = true;
|
slashManualScrolled.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -766,6 +787,9 @@ const closeSlashMenu = () => {
|
|||||||
cancelAnimationFrame(slashAnimId);
|
cancelAnimationFrame(slashAnimId);
|
||||||
slashAnimId = null;
|
slashAnimId = null;
|
||||||
}
|
}
|
||||||
|
slashAnimating = false;
|
||||||
|
lastSlashAnimatedScroll = null;
|
||||||
|
lastSlashAnimationEndTime = 0;
|
||||||
skillSlashOpen.value = false;
|
skillSlashOpen.value = false;
|
||||||
skillSlashQuery.value = '';
|
skillSlashQuery.value = '';
|
||||||
skillSlashActiveIndex.value = 0;
|
skillSlashActiveIndex.value = 0;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user