Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.
Vue Router is a URL router that maps URLs to components.
In this article, we’ll look at how to change the scroll behavior of Vue Router routes.
Changing Scroll Behavior
Sometimes we may want to scroll to top when navigating to a new route or preserve the scrolling position of history entities like a real page reload.
Vue Router lets us adjust the scrolling behavior the way we like when route loads.
This only works if the browser supports history.pushState
.
We can adjust scrolling behavior by providing a scrollBehavior
function.
It has a to
and from
route objects as the first 2 parameters. The third argument is savePosition
, is only available if this is a popstate
navigation triggered by the browser’s back or forward buttons.
The function can return a scroll position object in the form of:
{ x: number, y: number }
or:
{ selector: string, offset? : { x: number, y: number }}
offset
is supported since Vue Router 2.6.0
For example, we can add scrollBehavior
to our routes as follows:
src/index.js:
const Foo = {
template: `
<div>
<div v-for='n in 100'>{{n}} foo</div>
</div>
`
};
const Bar = {
template: `
<div>
<div v-for='n in 100'>{{n}} bar</div>
</div>
`
};
const routes = [
{
path: "/foo",
component: Foo
},
{
path: "/bar",
component: Bar
}
];
const router = new VueRouter({
routes,
scrollBehavior(to, from, savedPosition) {
return { x: 0, y: 0 };
}
});new Vue({
el: "#app",
router
});
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<router-view></router-view>
<router-link to="foo">Foo</router-link>
<router-link to="bar">Bar</router-link>
</div>
<script src="src/index.js"></script>
</body>
</html>
In the code above, we have:
scrollBehavior(to, from, savedPosition) {
return { x: 0, y: 0 };
}
to scroll the next page back to the top when we navigate. Therefore, when we click on the links at the bottom of the page, we’ll go back to the top.
If we return something falsy or an empty object, no scrolling will happen.
If we change scrollBehavior
to:
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
} else {
return { x: 0, y: 0 };
}
}
Then we keep the scroll position of the page when we navigate back and forth with the forward and back buttons.
We can create the scroll to anchor behavior by setting the ID on our elements and then changing scrollBehavior
as follows:
src/index.js
:
const Foo = {
template: `
<div>
<div v-for='n in 100' :id='n'>{{n}} foo</div>
</div>
`
};
const routes = [
{
path: "/foo",
component: Foo
}
];
const router = new VueRouter({
routes,
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return {
selector: to.hash
};
}
}
});
new Vue({
el: "#app",
router
});
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<router-view></router-view>
</div>
<script src="src/index.js"></script>
</body>
</html>
Then when we go to /#/foo#100
we scroll to the bottom, then when we go to /#/foo#20
, we see 20 foo
at the top of the screen.
Async Scrolling
We can also to async scrolling with scrollBehavior
since Vue Router 2.8.0 by returning a promise that resolves to the same objects as synchronous scrolling.
For example, we can change the example above to:
src/index.js
:
const Foo = {
template: `
<div>
<div v-for='n in 100' :id='n'>{{n}} foo</div>
</div>
`
};
const routes = [
{
path: "/foo",
component: Foo
}
];
const router = new VueRouter({
routes,
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
selector: to.hash
});
}, 1000);
});
}
}
});
new Vue({
el: "#app",
router
});
Then when we go to /#/foo#100
in our browser, we scroll to the bottom of the page after a second.
Conclusion
Scrolling behavior during route navigation can be changed by adding a scrollBehavior
function to our router
object. It takes the to
and from
parameters which are route objects, and a 3rd savedPosition
parameter with the saved scroll position of the navigated route.
Scrolling behavior can be synchronous or asynchronous since Vue Router 2.8.0.
We can scroll to an element with the CSS selector or position.