Skip to content

Commit 67ffb9f

Browse files
author
Taois
committed
feat:据搜页面恢复机制,就像用户从未离开过
1 parent be59892 commit 67ffb9f

File tree

3 files changed

+228
-31
lines changed

3 files changed

+228
-31
lines changed

dashboard/src/stores/pageStateStore.js

Lines changed: 87 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,65 @@
11
import { defineStore } from 'pinia';
22

3+
// SessionStorage键名常量
4+
const STORAGE_KEY = 'drplayer_page_states';
5+
6+
// 从SessionStorage加载状态
7+
const loadFromStorage = () => {
8+
try {
9+
const stored = sessionStorage.getItem(STORAGE_KEY);
10+
if (stored) {
11+
const parsed = JSON.parse(stored);
12+
console.log('🔄 [存储] 从SessionStorage加载页面状态:', parsed);
13+
return parsed;
14+
}
15+
} catch (error) {
16+
console.error('从SessionStorage加载页面状态失败:', error);
17+
}
18+
19+
// 返回默认状态
20+
return {
21+
// Video页面状态
22+
video: {
23+
activeKey: '',
24+
currentPage: 1,
25+
videos: [],
26+
hasMore: true,
27+
loading: false,
28+
scrollPosition: 0,
29+
lastUpdateTime: null
30+
},
31+
// Home页面状态
32+
home: {
33+
scrollPosition: 0,
34+
lastUpdateTime: null
35+
},
36+
// 搜索结果状态
37+
search: {
38+
keyword: '',
39+
currentPage: 1,
40+
videos: [],
41+
hasMore: true,
42+
loading: false,
43+
scrollPosition: 0,
44+
lastUpdateTime: null
45+
}
46+
};
47+
};
48+
49+
// 保存到SessionStorage
50+
const saveToStorage = (pageStates) => {
51+
try {
52+
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(pageStates));
53+
console.log('🔄 [存储] 保存页面状态到SessionStorage:', pageStates);
54+
} catch (error) {
55+
console.error('保存页面状态到SessionStorage失败:', error);
56+
}
57+
};
58+
359
export const usePageStateStore = defineStore('pageState', {
460
state: () => ({
5-
// 保存各个页面的状态
6-
pageStates: {
7-
// Video页面状态
8-
video: {
9-
activeKey: '',
10-
currentPage: 1,
11-
videos: [],
12-
hasMore: true,
13-
loading: false,
14-
scrollPosition: 0,
15-
lastUpdateTime: null
16-
},
17-
// Home页面状态
18-
home: {
19-
scrollPosition: 0,
20-
lastUpdateTime: null
21-
},
22-
// 搜索结果状态
23-
search: {
24-
keyword: '',
25-
currentPage: 1,
26-
videos: [],
27-
hasMore: true,
28-
loading: false,
29-
scrollPosition: 0,
30-
lastUpdateTime: null
31-
}
32-
}
61+
// 保存各个页面的状态,从SessionStorage初始化
62+
pageStates: loadFromStorage()
3363
}),
3464

3565
actions: {
@@ -46,7 +76,10 @@ export const usePageStateStore = defineStore('pageState', {
4676
lastUpdateTime: Date.now()
4777
};
4878

49-
console.log(`保存页面状态 [${pageName}]:`, this.pageStates[pageName]);
79+
// 立即保存到SessionStorage
80+
saveToStorage(this.pageStates);
81+
82+
console.log(`🔄 [状态保存] 页面状态 [${pageName}]:`, this.pageStates[pageName]);
5083
},
5184

5285
// 获取页面状态
@@ -60,7 +93,11 @@ export const usePageStateStore = defineStore('pageState', {
6093
clearPageState(pageName) {
6194
if (this.pageStates[pageName]) {
6295
this.pageStates[pageName] = {};
63-
console.log(`清除页面状态 [${pageName}]`);
96+
97+
// 同步到SessionStorage
98+
saveToStorage(this.pageStates);
99+
100+
console.log(`🔄 [状态清除] 页面状态 [${pageName}]`);
64101
}
65102
},
66103

@@ -102,13 +139,33 @@ export const usePageStateStore = defineStore('pageState', {
102139
if (this.pageStates[pageName]) {
103140
this.pageStates[pageName].scrollPosition = position;
104141
this.pageStates[pageName].lastUpdateTime = Date.now();
142+
143+
// 同步到SessionStorage
144+
saveToStorage(this.pageStates);
105145
}
106146
},
107147

108148
// 获取滚动位置
109149
getScrollPosition(pageName) {
110150
const state = this.pageStates[pageName];
111151
return state ? state.scrollPosition || 0 : 0;
152+
},
153+
154+
// 重新从SessionStorage加载状态
155+
reloadFromStorage() {
156+
this.pageStates = loadFromStorage();
157+
console.log('🔄 [存储] 重新加载页面状态:', this.pageStates);
158+
},
159+
160+
// 清除所有SessionStorage数据
161+
clearAllStorage() {
162+
try {
163+
sessionStorage.removeItem(STORAGE_KEY);
164+
this.pageStates = loadFromStorage(); // 重置为默认状态
165+
console.log('🔄 [存储] 清除所有页面状态');
166+
} catch (error) {
167+
console.error('清除SessionStorage失败:', error);
168+
}
112169
}
113170
},
114171

dashboard/src/views/SearchAggregation.vue

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@
262262
</template>
263263

264264
<script>
265-
import { defineComponent, ref, computed, onMounted, onUnmounted, watch } from 'vue';
265+
import { defineComponent, ref, computed, onMounted, onUnmounted, onBeforeUnmount, watch, nextTick } from 'vue';
266266
import { useRoute, useRouter } from 'vue-router';
267267
import { Message } from '@arco-design/web-vue';
268268
import {
@@ -611,6 +611,9 @@ export default defineComponent({
611611
const scrollHeight = container.scrollHeight - container.clientHeight;
612612
const scrollTop = container.scrollTop;
613613
614+
// 实时更新滚动位置
615+
scrollPosition.value = scrollTop;
616+
614617
// 当滚动到距离底部50px以内时触发加载
615618
if (scrollHeight - scrollTop < 50 && hasMoreData.value && !loadingMore.value) {
616619
loadMore();
@@ -725,6 +728,12 @@ export default defineComponent({
725728
tempSiteExt: currentSource.ext,
726729
fromSpecialAction: 'true',
727730
from: 'search-aggregation',
731+
// 添加来源页面信息,用于返回时恢复状态
732+
sourceRouteName: 'SearchAggregation',
733+
sourceRouteParams: JSON.stringify({}),
734+
sourceRouteQuery: JSON.stringify({
735+
keyword: searchKeyword.value
736+
}),
728737
// 添加来源图片信息,用于详情页图片备用
729738
sourcePic: video.pic
730739
}
@@ -976,6 +985,98 @@ export default defineComponent({
976985
}
977986
});
978987
988+
// 滚动位置状态
989+
const scrollPosition = ref(0);
990+
991+
// 保存滚动位置
992+
const saveScrollPosition = () => {
993+
const scrollContainer = scrollbarRef.value?.$el?.querySelector('.arco-scrollbar-container');
994+
if (scrollContainer) {
995+
scrollPosition.value = scrollContainer.scrollTop;
996+
console.log('🔄 [滚动位置] 保存滚动位置:', scrollPosition.value);
997+
}
998+
};
999+
1000+
// 恢复滚动位置
1001+
const restoreScrollPosition = () => {
1002+
if (scrollPosition.value > 0) {
1003+
nextTick(() => {
1004+
const scrollContainer = scrollbarRef.value?.$el?.querySelector('.arco-scrollbar-container');
1005+
if (scrollContainer) {
1006+
scrollContainer.scrollTop = scrollPosition.value;
1007+
console.log('🔄 [滚动位置] 恢复滚动位置:', scrollPosition.value);
1008+
}
1009+
});
1010+
}
1011+
};
1012+
1013+
// 状态保存和恢复
1014+
const savePageState = () => {
1015+
if (hasSearched.value && searchKeyword.value) {
1016+
// 保存当前滚动位置
1017+
saveScrollPosition();
1018+
1019+
const state = {
1020+
searchKeyword: searchKeyword.value,
1021+
hasSearched: hasSearched.value,
1022+
searchResults: searchResults.value,
1023+
loadingStates: loadingStates.value,
1024+
errorStates: errorStates.value,
1025+
activeSource: activeSource.value,
1026+
currentPages: currentPages.value,
1027+
hasMorePages: hasMorePages.value,
1028+
searchCompletedTimes: searchCompletedTimes.value,
1029+
displayedCount: displayedCount.value,
1030+
scrollPosition: scrollPosition.value,
1031+
scrollAreaHeight: scrollAreaHeight.value,
1032+
loadingMore: loadingMore.value
1033+
};
1034+
pageStateStore.savePageState('searchAggregation', state);
1035+
console.log('🔄 [状态保存] 保存聚合搜索页面状态:', state);
1036+
}
1037+
};
1038+
1039+
const restorePageState = () => {
1040+
const savedState = pageStateStore.getPageState('searchAggregation');
1041+
if (savedState && !pageStateStore.isStateExpired('searchAggregation')) {
1042+
console.log('🔄 [状态恢复] 恢复聚合搜索页面状态:', savedState);
1043+
1044+
searchKeyword.value = savedState.searchKeyword || '';
1045+
hasSearched.value = savedState.hasSearched || false;
1046+
searchResults.value = savedState.searchResults || {};
1047+
loadingStates.value = savedState.loadingStates || {};
1048+
errorStates.value = savedState.errorStates || {};
1049+
activeSource.value = savedState.activeSource || '';
1050+
currentPages.value = savedState.currentPages || {};
1051+
hasMorePages.value = savedState.hasMorePages || {};
1052+
searchCompletedTimes.value = savedState.searchCompletedTimes || {};
1053+
displayedCount.value = savedState.displayedCount || 20;
1054+
loadingMore.value = savedState.loadingMore || false;
1055+
1056+
// 恢复滚动位置和区域高度
1057+
scrollPosition.value = savedState.scrollPosition || 0;
1058+
if (savedState.scrollAreaHeight) {
1059+
scrollAreaHeight.value = savedState.scrollAreaHeight;
1060+
}
1061+
1062+
// 更新全局统计信息
1063+
updateGlobalStats();
1064+
1065+
// 延迟恢复滚动位置,确保DOM已渲染
1066+
if (scrollPosition.value > 0) {
1067+
// 使用多重延迟确保搜索结果完全渲染
1068+
nextTick(() => {
1069+
setTimeout(() => {
1070+
restoreScrollPosition();
1071+
}, 200);
1072+
});
1073+
}
1074+
1075+
return true;
1076+
}
1077+
return false;
1078+
};
1079+
9791080
// 组件挂载时初始化
9801081
onMounted(() => {
9811082
loadSearchSources();
@@ -991,8 +1092,43 @@ export default defineComponent({
9911092
if (settings.selectedSources.length > 0) {
9921093
console.log(`已恢复搜索源配置,共 ${settings.selectedSources.length} 个源`);
9931094
}
1095+
1096+
// 检查是否从详情页返回
1097+
const isReturnFromDetail = route.query._returnFromDetail === 'true';
1098+
console.log('🔄 [状态恢复] 是否从详情页返回:', isReturnFromDetail);
1099+
1100+
// 尝试恢复页面状态
1101+
const restored = restorePageState();
1102+
if (restored) {
1103+
console.log('🔄 [状态恢复] 成功恢复聚合搜索页面状态');
1104+
1105+
// 如果是从详情页返回,优先使用恢复的状态,不执行新搜索
1106+
if (isReturnFromDetail) {
1107+
console.log('🔄 [状态恢复] 从详情页返回,使用恢复的状态,不执行新搜索');
1108+
} else if (route.query.keyword && route.query.keyword !== searchKeyword.value) {
1109+
// 如果不是从详情页返回,且URL中有不同的关键词,则执行新的搜索
1110+
console.log('🔄 [状态恢复] URL关键词与恢复状态不同,执行新搜索:', route.query.keyword);
1111+
performSearch(route.query.keyword);
1112+
}
1113+
} else if (route.query.keyword) {
1114+
// 如果没有恢复状态但URL中有关键词,则执行搜索
1115+
console.log('🔄 [状态恢复] 没有保存状态,根据URL关键词执行搜索:', route.query.keyword);
1116+
performSearch(route.query.keyword);
1117+
}
1118+
1119+
// 清理URL中的返回标识
1120+
if (isReturnFromDetail) {
1121+
const newQuery = { ...route.query };
1122+
delete newQuery._returnFromDetail;
1123+
router.replace({ query: newQuery });
1124+
}
9941125
});
9951126
1127+
onBeforeUnmount(() => {
1128+
// 页面离开前保存状态
1129+
savePageState();
1130+
});
1131+
9961132
onUnmounted(() => {
9971133
window.removeEventListener('resize', updateScrollAreaHeight);
9981134
});

dashboard/src/views/VideoDetail.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,10 @@ const goBack = () => {
946946
console.log('发现保存的Video页面状态,将恢复状态而非重新加载');
947947
}
948948
}
949+
} else if (sourceRouteName === 'SearchAggregation') {
950+
// 返回聚合搜索页面,添加返回标识
951+
console.log('从聚合搜索页面返回,添加返回标识');
952+
query._returnFromDetail = 'true';
949953
} else if (sourceRouteName === 'Home') {
950954
// 返回Home页面,检查搜索状态
951955
const savedSearchState = pageStateStore.getPageState('search');

0 commit comments

Comments
 (0)