feat: Enhance scrolling behavior with pause before refresh
- Introduced a pause mechanism at the end of scrolling for both Ladder and Ranking boards, allowing the last item to be fully visible before triggering a data refresh. - Updated scrolling logic to prevent immediate resets, improving user experience during data loading. - Added a consistent pause duration across components to standardize behavior during scrolling interactions.
This commit is contained in:
parent
f861f82675
commit
ccea3a99e5
@ -243,6 +243,7 @@ const boardsScrollY = ref(0);
|
||||
const matchesScrollY = ref(0);
|
||||
|
||||
const REFRESH_COOLDOWN_MS = 3000;
|
||||
const PAUSE_AT_END_MS = 2800; // 到底后停留,让最后一项完整露出后再刷新
|
||||
let lastRefreshAt = 0;
|
||||
|
||||
const onScrollEndRefresh = () => {
|
||||
@ -360,6 +361,8 @@ const startBoardsScroll = () => {
|
||||
if (!boardsScrollEl.value || !boardsGroup1.value) return;
|
||||
if (loadingBoards.value) return;
|
||||
|
||||
let boardsPauseScheduled = false;
|
||||
|
||||
const tick = () => {
|
||||
if (!boardsScrollEl.value || !boardsGroup1.value) {
|
||||
boardsRaf = requestAnimationFrame(tick);
|
||||
@ -369,6 +372,10 @@ const startBoardsScroll = () => {
|
||||
boardsRaf = requestAnimationFrame(tick);
|
||||
return;
|
||||
}
|
||||
if (boardsPauseScheduled) {
|
||||
boardsRaf = requestAnimationFrame(tick);
|
||||
return;
|
||||
}
|
||||
|
||||
const h = boardsGroup1.value.offsetHeight;
|
||||
const containerH = boardsScrollEl.value.offsetHeight;
|
||||
@ -380,8 +387,15 @@ const startBoardsScroll = () => {
|
||||
|
||||
boardsScrollY.value -= 0.35;
|
||||
if (Math.abs(boardsScrollY.value) >= h) {
|
||||
boardsScrollY.value = 0;
|
||||
boardsScrollY.value = -h;
|
||||
if (!boardsPauseScheduled) {
|
||||
boardsPauseScheduled = true;
|
||||
setTimeout(() => {
|
||||
onScrollEndRefresh();
|
||||
boardsScrollY.value = 0;
|
||||
boardsPauseScheduled = false;
|
||||
}, PAUSE_AT_END_MS);
|
||||
}
|
||||
}
|
||||
boardsRaf = requestAnimationFrame(tick);
|
||||
};
|
||||
@ -394,6 +408,8 @@ const startMatchesScroll = () => {
|
||||
if (!matchesScrollEl.value || !matchesGroup1.value) return;
|
||||
if (loadingMatches.value) return;
|
||||
|
||||
let matchesPauseScheduled = false;
|
||||
|
||||
const tick = () => {
|
||||
if (!matchesScrollEl.value || !matchesGroup1.value) {
|
||||
matchesRaf = requestAnimationFrame(tick);
|
||||
@ -403,6 +419,10 @@ const startMatchesScroll = () => {
|
||||
matchesRaf = requestAnimationFrame(tick);
|
||||
return;
|
||||
}
|
||||
if (matchesPauseScheduled) {
|
||||
matchesRaf = requestAnimationFrame(tick);
|
||||
return;
|
||||
}
|
||||
|
||||
const h = matchesGroup1.value.offsetHeight;
|
||||
const containerH = matchesScrollEl.value.offsetHeight;
|
||||
@ -414,8 +434,15 @@ const startMatchesScroll = () => {
|
||||
|
||||
matchesScrollY.value -= 0.4;
|
||||
if (Math.abs(matchesScrollY.value) >= h) {
|
||||
matchesScrollY.value = 0;
|
||||
matchesScrollY.value = -h;
|
||||
if (!matchesPauseScheduled) {
|
||||
matchesPauseScheduled = true;
|
||||
setTimeout(() => {
|
||||
onScrollEndRefresh();
|
||||
matchesScrollY.value = 0;
|
||||
matchesPauseScheduled = false;
|
||||
}, PAUSE_AT_END_MS);
|
||||
}
|
||||
}
|
||||
matchesRaf = requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
@ -243,6 +243,7 @@ const boardsScrollY = ref(0);
|
||||
const matchesScrollY = ref(0);
|
||||
|
||||
const REFRESH_COOLDOWN_MS = 3000;
|
||||
const PAUSE_AT_END_MS = 2800; // 到底后停留,让最后一项完整露出后再刷新
|
||||
let lastRefreshAt = 0;
|
||||
|
||||
const onScrollEndRefresh = () => {
|
||||
@ -360,6 +361,8 @@ const startBoardsScroll = () => {
|
||||
if (!boardsScrollEl.value || !boardsGroup1.value) return;
|
||||
if (loadingBoards.value) return;
|
||||
|
||||
let boardsPauseScheduled = false;
|
||||
|
||||
const tick = () => {
|
||||
if (!boardsScrollEl.value || !boardsGroup1.value) {
|
||||
boardsRaf = requestAnimationFrame(tick);
|
||||
@ -369,6 +372,10 @@ const startBoardsScroll = () => {
|
||||
boardsRaf = requestAnimationFrame(tick);
|
||||
return;
|
||||
}
|
||||
if (boardsPauseScheduled) {
|
||||
boardsRaf = requestAnimationFrame(tick);
|
||||
return;
|
||||
}
|
||||
|
||||
const h = boardsGroup1.value.offsetHeight;
|
||||
const containerH = boardsScrollEl.value.offsetHeight;
|
||||
@ -380,8 +387,15 @@ const startBoardsScroll = () => {
|
||||
|
||||
boardsScrollY.value -= 0.35;
|
||||
if (Math.abs(boardsScrollY.value) >= h) {
|
||||
boardsScrollY.value = 0;
|
||||
boardsScrollY.value = -h;
|
||||
if (!boardsPauseScheduled) {
|
||||
boardsPauseScheduled = true;
|
||||
setTimeout(() => {
|
||||
onScrollEndRefresh();
|
||||
boardsScrollY.value = 0;
|
||||
boardsPauseScheduled = false;
|
||||
}, PAUSE_AT_END_MS);
|
||||
}
|
||||
}
|
||||
boardsRaf = requestAnimationFrame(tick);
|
||||
};
|
||||
@ -394,6 +408,8 @@ const startMatchesScroll = () => {
|
||||
if (!matchesScrollEl.value || !matchesGroup1.value) return;
|
||||
if (loadingMatches.value) return;
|
||||
|
||||
let matchesPauseScheduled = false;
|
||||
|
||||
const tick = () => {
|
||||
if (!matchesScrollEl.value || !matchesGroup1.value) {
|
||||
matchesRaf = requestAnimationFrame(tick);
|
||||
@ -403,6 +419,10 @@ const startMatchesScroll = () => {
|
||||
matchesRaf = requestAnimationFrame(tick);
|
||||
return;
|
||||
}
|
||||
if (matchesPauseScheduled) {
|
||||
matchesRaf = requestAnimationFrame(tick);
|
||||
return;
|
||||
}
|
||||
|
||||
const h = matchesGroup1.value.offsetHeight;
|
||||
const containerH = matchesScrollEl.value.offsetHeight;
|
||||
@ -414,8 +434,15 @@ const startMatchesScroll = () => {
|
||||
|
||||
matchesScrollY.value -= 0.4;
|
||||
if (Math.abs(matchesScrollY.value) >= h) {
|
||||
matchesScrollY.value = 0;
|
||||
matchesScrollY.value = -h;
|
||||
if (!matchesPauseScheduled) {
|
||||
matchesPauseScheduled = true;
|
||||
setTimeout(() => {
|
||||
onScrollEndRefresh();
|
||||
matchesScrollY.value = 0;
|
||||
matchesPauseScheduled = false;
|
||||
}, PAUSE_AT_END_MS);
|
||||
}
|
||||
}
|
||||
matchesRaf = requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
@ -500,6 +500,7 @@
|
||||
const scrollYMale = ref(0);
|
||||
const scrollYFemale = ref(0);
|
||||
const REFRESH_COOLDOWN_MS = 3000;
|
||||
const PAUSE_AT_END_MS = 2800; // 到底后停留时长,让最后一名完整露出后再刷新
|
||||
let lastRefreshAt = 0;
|
||||
|
||||
// 更新时间
|
||||
@ -518,22 +519,37 @@
|
||||
const startContinuousScroll = (listRef, scrollYRef, reqIdRef) => {
|
||||
if (reqIdRef.value) cancelAnimationFrame(reqIdRef.value);
|
||||
|
||||
let pauseScheduled = false;
|
||||
|
||||
const scroll = () => {
|
||||
if (isRefreshing.value || listRef.value.length === 0) {
|
||||
reqIdRef.value = requestAnimationFrame(scroll);
|
||||
return;
|
||||
}
|
||||
|
||||
// 已到底并处于“停留展示最后一名”的暂停期,本帧不滚动
|
||||
if (pauseScheduled) {
|
||||
reqIdRef.value = requestAnimationFrame(scroll);
|
||||
return;
|
||||
}
|
||||
|
||||
// 每一帧移动的像素 (降低速度,使其更易阅读)
|
||||
scrollYRef.value -= 0.6;
|
||||
|
||||
// 计算单份数据的高度:100条 * (90px行高 + 12px间距)
|
||||
const singleSetHeight = listRef.value.length * 102;
|
||||
|
||||
// 如果滚完了一整套数据,瞬间重置回 0,并触发一次刷新
|
||||
// 滚完一整屏:先停在底部一段时间让最后一名露出,再刷新并重置
|
||||
if (Math.abs(scrollYRef.value) >= singleSetHeight) {
|
||||
scrollYRef.value = 0;
|
||||
scrollYRef.value = -singleSetHeight;
|
||||
if (!pauseScheduled) {
|
||||
pauseScheduled = true;
|
||||
setTimeout(() => {
|
||||
onScrollEndRefresh();
|
||||
scrollYRef.value = 0;
|
||||
pauseScheduled = false;
|
||||
}, PAUSE_AT_END_MS);
|
||||
}
|
||||
}
|
||||
|
||||
reqIdRef.value = requestAnimationFrame(scroll);
|
||||
|
||||
@ -549,6 +549,7 @@
|
||||
const scrollYMale = ref(0);
|
||||
const scrollYFemale = ref(0);
|
||||
const REFRESH_COOLDOWN_MS = 3000;
|
||||
const PAUSE_AT_END_MS = 2800; // 到底后停留时长,让最后一名完整露出后再刷新
|
||||
let lastRefreshAt = 0;
|
||||
|
||||
const updateTime = () => {
|
||||
@ -564,19 +565,33 @@
|
||||
const startContinuousScroll = (listRef, scrollYRef, reqIdRef, groupRef) => {
|
||||
if (reqIdRef.value) cancelAnimationFrame(reqIdRef.value);
|
||||
|
||||
let pauseScheduled = false;
|
||||
|
||||
const scroll = () => {
|
||||
if (isRefreshing.value || listRef.value.length <= 3 || !groupRef.value) {
|
||||
reqIdRef.value = requestAnimationFrame(scroll);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pauseScheduled) {
|
||||
reqIdRef.value = requestAnimationFrame(scroll);
|
||||
return;
|
||||
}
|
||||
|
||||
scrollYRef.value -= 0.6;
|
||||
|
||||
const singleSetHeight = groupRef.value.offsetHeight + 12;
|
||||
|
||||
if (Math.abs(scrollYRef.value) >= singleSetHeight) {
|
||||
scrollYRef.value = 0;
|
||||
scrollYRef.value = -singleSetHeight;
|
||||
if (!pauseScheduled) {
|
||||
pauseScheduled = true;
|
||||
setTimeout(() => {
|
||||
onScrollEndRefresh();
|
||||
scrollYRef.value = 0;
|
||||
pauseScheduled = false;
|
||||
}, PAUSE_AT_END_MS);
|
||||
}
|
||||
}
|
||||
|
||||
reqIdRef.value = requestAnimationFrame(scroll);
|
||||
|
||||
@ -226,6 +226,12 @@ class UserController {
|
||||
updateData.gender = normalizedGender;
|
||||
|
||||
await existingUser.update(updateData);
|
||||
if (nickname) {
|
||||
await LadderUser.update(
|
||||
{ real_name: nickname },
|
||||
{ where: { user_id: existingUser.id } },
|
||||
);
|
||||
}
|
||||
user = existingUser;
|
||||
} else {
|
||||
// 新用户注册
|
||||
@ -260,7 +266,12 @@ class UserController {
|
||||
updateData.gender = normalizedGender;
|
||||
|
||||
await user.update(updateData);
|
||||
|
||||
if (nickname) {
|
||||
await LadderUser.update(
|
||||
{ real_name: nickname },
|
||||
{ where: { user_id: user.id } },
|
||||
);
|
||||
}
|
||||
// 如果手机号变化,重新关联天梯用户
|
||||
await this.linkLadderUsers(user.id, phone);
|
||||
}
|
||||
@ -371,6 +382,14 @@ class UserController {
|
||||
|
||||
await user.update(updateData);
|
||||
|
||||
// 用户修改昵称时,同步更新该用户下所有天梯用户的 real_name,保持两边一致
|
||||
if (nickname) {
|
||||
await LadderUser.update(
|
||||
{ real_name: nickname },
|
||||
{ where: { user_id: user.id } },
|
||||
);
|
||||
}
|
||||
|
||||
res.json(
|
||||
success(
|
||||
{
|
||||
@ -447,13 +466,21 @@ class UserController {
|
||||
const { nickname, avatar, phone, gender } = req.body;
|
||||
const user = req.user;
|
||||
|
||||
const newNickname = nickname || user.nickname;
|
||||
await user.update({
|
||||
nickname: nickname || user.nickname,
|
||||
nickname: newNickname,
|
||||
avatar: avatar || user.avatar,
|
||||
phone: phone || user.phone,
|
||||
gender: gender !== undefined ? gender : user.gender,
|
||||
});
|
||||
|
||||
if (nickname) {
|
||||
await LadderUser.update(
|
||||
{ real_name: nickname },
|
||||
{ where: { user_id: user.id } },
|
||||
);
|
||||
}
|
||||
|
||||
res.json(success(null, "更新成功"));
|
||||
} catch (err) {
|
||||
console.error("更新用户信息失败:", err);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user