Skip to content

Commit 74f3c59

Browse files
authored
Merge pull request #147 from LostElkByte/main
feat: add scroll-cache demo
2 parents 1ce0ee3 + 9ce5c1f commit 74f3c59

File tree

10 files changed

+248
-1
lines changed

10 files changed

+248
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ stats.html
2323

2424
# Misc
2525
.DS_Store
26+
.history

postcss.config.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ export default {
88
appSelector: '#app',
99
viewportWidth: 375,
1010
maxDisplayWidth: 600,
11-
appContainingBlock: 'auto',
1211
border: true,
12+
rootContainingBlockSelectorList: [
13+
'van-tabbar',
14+
'van-popup',
15+
],
1316
},
1417
},
1518
}

src/locales/en-US.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"persistPiniaState": "🍍 Persistent Pinia state",
1111
"unocssExample": "🎨 Unocss example",
1212
"keepAlive": "🧡 KeepAlive Demo",
13+
"scrollCache": "📜 Scroll Cache Demo",
1314
"login": "🔒 Login",
1415
"register": "Register",
1516
"settings": "Settings",
@@ -43,6 +44,9 @@
4344
"keepAlive": {
4445
"label": "The current component will be cached"
4546
},
47+
"scrollCache": {
48+
"listItem": "Slide freely. When you get back, the roll position will still be there"
49+
},
4650
"login": {
4751
"login": "Sign In",
4852
"logout": "Sign Out",

src/locales/zh-CN.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"404Demo": "🙅 404页 演示",
1111
"unocssExample": "🎨 Unocss 示例",
1212
"keepAlive": "🧡 KeepAlive 演示",
13+
"scrollCache": "📜 滚动缓存 演示",
1314
"login": "🔒 用户登录",
1415
"register": "用户注册",
1516
"settings": "设置",
@@ -43,6 +44,9 @@
4344
"keepAlive": {
4445
"label": "当前组件将会被缓存"
4546
},
47+
"scrollCache": {
48+
"listItem": "随便滑滑,离开再回来时位置会保留不变哦"
49+
},
4650
"login": {
4751
"login": "登录",
4852
"logout": "退出",

src/pages/index.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const menuItems = computed(() => ([
1010
{ title: t('menus.unocssExample'), route: 'unocss' },
1111
{ title: t('menus.persistPiniaState'), route: 'counter' },
1212
{ title: t('menus.keepAlive'), route: 'keepalive' },
13+
{ title: t('menus.scrollCache'), route: 'scroll-cache' },
1314
{ title: t('menus.404Demo'), route: 'unknown' },
1415
]))
1516

src/pages/scroll-cache/README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Page Scroll Position Save and Restore Guide
2+
3+
If you want to save the current scroll position when leaving a page and restore it upon return, you can follow the approach outlined below.
4+
5+
## Basic Approach
6+
7+
1. **Cache the Component**:
8+
Set `keepAlive` to `true` to cache the component.
9+
10+
2. **Save Scroll Position**:
11+
Use the `onBeforeRouteLeave` hook to save the current scroll position when leaving the page.
12+
13+
3. **Restore Scroll Position**:
14+
Use the `onActivated` hook to restore the last saved scroll position when the page is activated.
15+
16+
## Example Code
17+
18+
```js
19+
// Define a ref to store the scroll position
20+
const scrollTop = ref(0)
21+
22+
// When a component with keepAlive set to true is activated, scroll to the saved position
23+
onActivated(() => {
24+
window.scrollTo(0, scrollTop.value)
25+
})
26+
27+
// Before leaving the route, save the current scroll position
28+
onBeforeRouteLeave(() => {
29+
scrollTop.value
30+
= window.scrollY
31+
|| document.documentElement.scrollTop
32+
|| document.body.scrollTop
33+
})
34+
```
35+
36+
# Handling a Specific Scroll Container
37+
38+
If you need to save and restore the scroll position for a specific element (instead of the entire window), follow these steps:
39+
40+
## 1. Add a ref in the Template
41+
42+
In your template, add a `ref` attribute to the scroll container element. For example:
43+
44+
```html
45+
<div ref="scrollContainer" class="...">...</div>
46+
47+
```
48+
49+
## 2. In the setup Function
50+
51+
Use a ref to obtain the element's reference:
52+
53+
```js
54+
const scrollContainer = ref(null)
55+
```
56+
57+
## 3. In the onBeforeRouteLeave Hook
58+
59+
Save the scroll container's scroll position:
60+
61+
```js
62+
onBeforeRouteLeave(() => {
63+
if (scrollContainer.value) {
64+
scrollTop.value = scrollContainer.value.scrollTop
65+
}
66+
})
67+
```
68+
69+
## 3. In the onActivated Hook
70+
71+
Restore the scroll container's scroll position:
72+
73+
```js
74+
onActivated(() => {
75+
if (scrollContainer.value) {
76+
scrollContainer.value.scrollTop = scrollTop.value
77+
}
78+
})
79+
```
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# 页面滚动位置保存与恢复指南
2+
3+
如果你希望在离开页面时保存当前的滚动位置,并在返回时恢复它,可以参考下面的实现思路:
4+
5+
## 基本思路
6+
7+
1. **缓存组件**
8+
设置 `keepAlive``true` 以缓存组件。
9+
10+
2. **保存滚动位置**
11+
在页面离开时,使用 `onBeforeRouteLeave` 钩子保存当前滚动位置。
12+
13+
3. **恢复滚动位置**
14+
在页面激活时,使用 `onActivated` 钩子恢复上次的滚动位置。
15+
16+
## 示例代码
17+
18+
```js
19+
// 定义一个 ref 用于存储滚动位置
20+
const scrollTop = ref(0)
21+
22+
// 当 keepAlive 为 true 的组件被激活时,滚动到保存的位置
23+
onActivated(() => {
24+
window.scrollTo(0, scrollTop.value)
25+
})
26+
27+
// 在路由离开前,保存当前的滚动位置
28+
onBeforeRouteLeave(() => {
29+
scrollTop.value
30+
= window.scrollY
31+
|| document.documentElement.scrollTop
32+
|| document.body.scrollTop
33+
})
34+
```
35+
36+
# 针对指定滚动容器的处理
37+
38+
如果你需要对特定元素(而非整个窗口)进行滚动位置的保存和恢复,可按以下步骤操作:
39+
40+
## 1. 在 Template 中添加 ref
41+
42+
在模板中,给滚动容器元素添加 `ref` 属性。例如:
43+
44+
```html
45+
<div ref="scrollContainer" class="...">...</div>
46+
```
47+
48+
## 2. 在 setup 中:
49+
50+
使用 ref 获取该元素的引用:
51+
52+
```js
53+
const scrollContainer = ref(null)
54+
```
55+
56+
## 3. 在 onBeforeRouteLeave 钩子中:
57+
58+
保存滚动容器的滚动位置:
59+
60+
```js
61+
onBeforeRouteLeave(() => {
62+
if (scrollContainer.value) {
63+
scrollTop.value = scrollContainer.value.scrollTop
64+
}
65+
})
66+
```
67+
68+
## 3. 在 onActivated 钩子中:
69+
70+
恢复滚动容器的滚动位置:
71+
72+
```js
73+
onActivated(() => {
74+
if (scrollContainer.value) {
75+
scrollContainer.value.scrollTop = scrollTop.value
76+
}
77+
})
78+
```
79+
80+
万事 OK 👌🏻

src/pages/scroll-cache/index.vue

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<script setup lang="ts">
2+
defineOptions({
3+
name: 'ScrollCache',
4+
})
5+
6+
const list = ref([])
7+
const loading = ref(false)
8+
const finished = ref(false)
9+
const { t } = useI18n()
10+
11+
function onLoad() {
12+
setTimeout(() => {
13+
for (let i = 0; i < 10; i++) {
14+
list.value.push(`${list.value.length + 1}`)
15+
}
16+
17+
loading.value = false
18+
19+
if (list.value.length >= 40) {
20+
finished.value = true
21+
}
22+
}, 1000)
23+
}
24+
25+
const scrollTop = ref(0)
26+
27+
onActivated(() => {
28+
window.scrollTo(0, scrollTop.value)
29+
})
30+
31+
onBeforeRouteLeave(() => {
32+
scrollTop.value
33+
= window.scrollY
34+
|| document.documentElement.scrollTop
35+
|| document.body.scrollTop
36+
})
37+
</script>
38+
39+
<template>
40+
<van-list
41+
v-model:loading="loading"
42+
:finished="finished"
43+
finished-text="已经到底啦 ~"
44+
loading-text="加载中..."
45+
@load="onLoad"
46+
>
47+
<van-cell
48+
v-for="(item, index) in list"
49+
:key="index"
50+
:border="false"
51+
class="mb-8 rounded-12"
52+
>
53+
<template #title>
54+
{{ t('scrollCache.listItem') }}
55+
</template>
56+
57+
<template #value>
58+
{{ item }}
59+
</template>
60+
</van-cell>
61+
</van-list>
62+
</template>
63+
64+
<route lang="json5">
65+
{
66+
name: 'ScrollCache',
67+
meta: {
68+
title: '📜 ScrollCache',
69+
i18n: 'menus.scrollCache',
70+
keepAlive: true
71+
},
72+
}
73+
</route>

src/types/components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ declare module 'vue' {
2323
VanForm: typeof import('vant/es')['Form']
2424
VanIcon: typeof import('vant/es')['Icon']
2525
VanImage: typeof import('vant/es')['Image']
26+
VanList: typeof import('vant/es')['List']
2627
VanNavBar: typeof import('vant/es')['NavBar']
2728
VanPicker: typeof import('vant/es')['Picker']
2829
VanPopup: typeof import('vant/es')['Popup']

src/types/typed-router.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ declare module 'vue-router/auto-routes' {
2828
'mock': RouteRecordInfo<'mock', '/mock', Record<never, never>, Record<never, never>>,
2929
'profile': RouteRecordInfo<'profile', '/profile', Record<never, never>, Record<never, never>>,
3030
'register': RouteRecordInfo<'register', '/register', Record<never, never>, Record<never, never>>,
31+
'ScrollCache': RouteRecordInfo<'ScrollCache', '/scroll-cache', Record<never, never>, Record<never, never>>,
3132
'settings': RouteRecordInfo<'settings', '/settings', Record<never, never>, Record<never, never>>,
3233
'unocss': RouteRecordInfo<'unocss', '/unocss', Record<never, never>, Record<never, never>>,
3334
}

0 commit comments

Comments
 (0)