We will encounter a problem in actual development:
we scroll down on a long list page, and then click on a certain data in the list to enter the details page to view. At this point we decided to go back to the list and continue looking at the list.
In many cases, because the components of the list page have been destroyed, when we return to the list page, the page will be on the top and we have to pull down to view the list again. This results in a lot of unnecessary operations and does not meet the user's expectations.
The user hopes to return after viewing the play details page. The position returned to the list page is the position just browsed.
What is a good solution to this situation?
Here are 3 solutions:
1. Use <keep-alive> cache, that is, do not destroy the list page
APP.js
<template>
<div id="app">
<!-- <router-view/> -->
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" />
</div>
</template>
router.js in
routes: [
{
path: '/',
name: 'List',
//component: List
component: () => import('./views/index/list.vue'),
meta: {
keepAlive: true // 需要缓存
}
},
{
path: '/content/:contentId',
name: 'content',
component: () => import('./views/index/content.vue'),
meta: {
keepAlive: false // 不需要缓存
}
},
]
The details page does not need to be cached, but the list page does.
2. Use route guards
The principle is to record the current page scroll position in the routing hook of beforeRouterLeave
//在页面离开时记录滚动位置,这里的this.scrollTop可以保存在vuex的state或者浏览器本地
beforeRouteLeave (to, from, next) {
this.scrollTop = document.documentElement.scrollTop || document.body.scrollTop
next()
},
//进入该页面时,用之前保存的滚动位置赋值
beforeRouteEnter (to, from, next) {
next(vm => {
document.body.scrollTop = vm.scrollTop
})
},
This.scrollTop here can be saved in the state of vuex or locally in the browser
3. Use vue-router method scrollBehavior (recommended)
router.js in
const scrollBehavior = function scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
// savedPosition 会在你使用浏览器前进或后退按钮时候生效
// savedPosition: 会记录滚动条的坐标,点击"后退/前进" 时的记录值(x:?,y:?)
return savedPosition;
}else {
return { x: 0, y: 0 }; // 期望滚动的位置
}
};
const router = new Router({
routes,
scrollBehavior,
});
This solution is processed directly in the routing, is compatible with every page, and does not generate a scroll position of 1px after the page is loaded.
scrollBehavior (to, from, savedPosition)
Methods to receiveto
andfrom
route objects. The third parameter is availablesavedPosition
if and only whenpopstate
navigating (triggered via the browser's forward/back buttons) .parameter:
to: The target routing object to enter, where to go
from: Where does the leaving routing object come from?
savedPosition: will record the coordinates of the scroll bar and the recorded value when "Back/Forward" is clicked (x:?,y:?)
scrolling behavior
We can vue-router
customize how the page scrolls when switching routes. For example, when jumping to a new route, the page scrolls to a certain position; when switching routes, the page returns to the previous scroll position.
When creating a route instance, we only need to provide a scrollBehavior
method:
const router = createRouter({
history: createWebHashHistory(),
routes: [...],
scrollBehavior (to, from, savedPosition) {
// return 期望滚动到哪个的位置
}
})
scrollBehavior
Functions receive to
and from
route objects. Third parameter , only available savedPosition
if this is a navigation (clicking the browser's back/forward buttons, or calling a method)popstate
router.go()
Scroll to a fixed distance
This function can return a ScrollToOptions
location object:
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
// 始终滚动到顶部
return { top: 0 }
},
})
Scroll to element position
This can be done by el
passing a CSS
selector or an DOM
element . In this case, top
and left
will be treated as the relative offset of that element.
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
// 始终在元素 #main 上方滚动 10px
return {
// el: document.getElementById('main'),
el: '#main',
top: -10,
}
},
})
Scroll to anchor position
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return {
el: to.hash,
}
}
},
})
Scroll to previous position
When the browser 后退/前进
button is pressed, or router.go()
a method is called, the page will return to the previous scroll position:
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { top: 0 }
}
},
})
Note: If false
a value of one is returned, or is one 空对象
, no scrolling will occur . We can also add it to the returned object behavior: 'smooth'
to make the scrolling smoother .
delayed scrolling
Sometimes we don't want the scrolling behavior to be performed immediately. For example, when the page has a transition effect, we hope that the scrolling will be performed after the transition is completed. To do this we can return a Promise
:
const router = createRouter({
scrollBehavior(to, from, savedPosition) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ left: 0, top: 0 })
}, 500)
})
}
})