I am trying to make Nuxt change routes and appear at the top of the new route, but without seeing it scrolling.
Right now it's either saving the last position, or it's changing the route while scrolling.
I don't want to see the page scrolling.
Setting this code in nuxt.config does nothing:
router: {
saveScrollPosition: false
}
Setting this code in app/router.scrollBehavior.js scrolls to top visibly:
export default function (to, from, savedPosition) {
return { x: 0, y: 0 }
}
Nuxt version 2.15.8
Vue version 2.7.10
Related
I'm trying to always go on the top of the page when route changes with Nuxt.
So I've put this into my app/router.scrollBehavior.js file:
export default function (to, from, savedPosition) {
return { x: 0, y: 0 }
}
But it always returns to the last saved position (which is always null in my console by the way).
Any idea of what I could miss here?
For Nuxt v3.0.0-rc.3
Create file named route.global.ts on middleware/ folder
Then write this in file:
export default defineNuxtRouteMiddleware((to, from) => {
if (to.path !== from.path && process.client) {
window.scrollTo(0, 0)
}
})
I use Nuxt 3 (npm:nuxt3#3.0.0-rc.4-27588443.cf25525), none of the solutions work for me.
Finally this works:
/plugins/scrollToTop.js (any filename will work, just put it in the plugins folder)
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.$router.options.scrollBehavior = async (to, from, savedPosition) => {
if (to.path !== from.path && process.client) {
window.scrollTo(0, 0);
}
};
});
According to the documentation:
https://nuxtjs.org/docs/configuration-glossary/configuration-router#scrollbehavior
The router.scrollBehavior.js file must be in the app folder, which in turn is in the project's root.
the file should name router.scrollBehavior.js.
You can console.log something in this function and check if it works.
At the end, GSAP was conflicting with OP's scrolling behavior.
Removing it, solved all the issues related to Nuxt, nothing was actually wrong with the router.scrollBehavior.js file.
The top answer is not the correct way of doing it.
Create a file in app directory called router.options.js
// app/router.options.js
export default {
scrollBehavior() {
return { top: 0 }
}
}
With typescript (recommended)
// app/router.options.ts
import type { RouterOptions } from '#nuxt/schema'
export default <RouterOptions> {
scrollBehavior() {
return { top: 0 }
}
}
For Nuxt 3
My solution was to create a file in the middleware folder with the following stucture:
export default defineNuxtRouteMiddleware((to, from) => {
useNuxtApp().hook("page:finish", () => {
if (history.state.scroll) {
setTimeout(() => window.scrollTo(history.state.scroll), 0);
} else {
setTimeout(() => window.scrollTo(0, 0), 0);
}
});
})
and I named it fix-scroll-position.global.ts.
The setTimeout is used to avoid the weird jumping to the top, meaning that the user won't see the page scrolling to the top.
This snippet ensures that the page scrolls to the top when the routes change, and that the scroll position is kept when the back button is clicked. The last functionality is achieved using history.state.scroll, that checks if there is a scroll position saved from the previous route.
I don't have enough reputation for a comment, so therefore an answer. A simple note, but I think it may help some.
I struggled with this as well and nothing worked, but after a while I found out the culprit. My layout looked like this
<template>
<div id="page" class="flex flex-col h-screen overflow-scroll bg-white">
<Navbar />
<slot />
<Footer />
</div>
</template>
That div around the components has the height of the screen and the page content scrolls in that div, but therefore the window is always at the top and you won't see any scrolling when clicking on NuxtLink.
I use nuxt 3.0.0 and when I let the #page div grow with the content (ie. removing the h-screen and overflow-scroll tailwind classes), it has the scroll to top behavior even without the solutions from above.
So, if you have this problem with the stable nuxt 3 version, check your html.
I'm trying to remember scroll position between routing pushes, NOT browser back/fwd navigation.
Case: on a long page of products, scrolling down and clicking on one of the items to see its details, then clicking a "back to list" button with a router push and (in my dreams) returning to where I was scrolled to on the product page.
This is my router. All the docs just give this basic config, but it doesn't work for me and I'm not sure if I need to add other logic in other components. Do I need to to save a 'savedPosition' in the state then get and set it in the router?
I'm also using beforeEach navigation guards but there isn't any scroll logic in there.
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
scrollBehavior(to, from, savedPosition) {
console.log("savedPosition", savedPosition);
if (savedPosition) {
return savedPosition;
} else {
return { x: 0, y: 0 };
}
},
});
I have the following code in one of my layouts.
bodyAttrs: {
class: this.$store.state.user.theme + '-scheme'
}
unfortunately, i am using an old bootstrap theme css. I DO NOT want to redo it as such i have to figure out some work arounds.
The theme color for the bootstrap theme attaches itself to the body tag. Unfortunately the body tag is a no no in nuxt.
What i have noticed is, that upon refresh the page is rendered with the base state value.
example :
//store/index.js <- not modular
var state = () => ({
user: {
id: 0,
avatar: 'default.jpg',
status: 'offline',
nickname: 'Guest',
admin: false,
theme: 'brownish' //-> this is the value
}
})
The entire page renders with the users details but the theme variable is not placed into the render. If i go to another page(ajax routing), the page is updated with the correct color.
Essentially the page loads brown and then on subsequent pages it will load blue. If the page is refreshed then the color reverts to brown and then on subsequent pages it will turn blue again.
How can i get the SSR to display the correct bodyAttr?
I am using vuex-persistedstate and cookies both are client side
The nuxt server does not have any sessions as this is handled on a separate domain(api)
I couldn't find a pure vuejs way to do this so i made a fix.
This is technically a bad idea as it is directly modifying the DOM which is a no-no in vue. However, vue doesnt use reactivity on the body tag. Therefore i think it is fairly safe to use. Also, using vuex-presistedstate will ensure that vue set the proper state variable on subsequent loads..
//This is layouts/default.vue
head() {
return {
bodyAttrs: {
class: this.$store.state.user.theme + '-scheme'
}
}
},
mounted() {
window.onNuxtReady(() => {
document.body.className = this.$store.state.user.theme + '-scheme'
})
}
Are you using the cookies based version of vuex-persistedstate? Customize Storage
Remember to enable the ssr mode for the plugin in nuxt.config.js
Without reloading the whole page I need to reload the current route again (Only a component reload) in a vue app.
I am having a path in vue router like below,
{
path: "/dashboard",
name: "dashboard",
component: loadView("Dashboard"),
},
When user clicks on the Dashboard navigation item user will be redirected to the Dashboard page with vue router programmatic navigation
this.$router.push({ name: "dashboard" });
But when user already in the dashboard route and user clicks the Dashboard nav item again nothing happens. I think this is vue router's default behaviour. But I need to force reload the Dashboard component (Not to refresh the whole page).
I can't use beforeRouteUpdate since the router is not updated. Also I have tried the global before guards like beforeEach. But it is also not working.
How can I force reload the dashboard component without reloading the whole page?
It can be done in two ways.
1) Try doing vm.$forceUpdate(); as suggested here.
2) You can take the strategy of assigning keys to children, but whenever you want to re-render a component, you just update the key.
<template>
<component-to-re-render :key="componentKey" />
</template>
<script>
export default {
data() {
return {
componentKey: 0,
};
},
methods: {
forceRerender() {
this.componentKey += 1;
}
}
}
</script>
Every time that forceRerender is called, the prop componentKey will change. When this happens, Vue will know that it has to destroy the component and create a new one.
What you get is a child component that will re-initialize itself and “reset” its state.
Not mentioned here, but as the offered solutions require a lot of additional work just to get the app to render correctly, which imo is a brittle solution.. we have just implemented another solution which works quite well..
Although it is a total hack.
if (this.$route.name === redirect.name) {
// this is a filthy hack - the vue router will not reload the current page and then have vue update the view.
// This hack routes to a generic page, then after this has happened the real redirect can happen
// It happens on most devices too fast to be noticed by the human eye, and in addition does not do a window
// redirect which breaks the mobile apps.
await this.$router.push({
name: RouteNames.ROUTE_REDIRECT_PLACEHOLDER
});
}
... now continue to do your normal redirect.
Essentially, redirect to a placeholder, await the response but then immediately continue to another page you actually wanted to move toward
I'm using Nuxt JS v2.4.5 with Bootstrap Vue, I have a fixed header and a page footer that are located inside of my default.vue file.
When I scroll to the bottom of a page and click a link in the footer, using the following, it takes me to the top of the new page as expected, however the content appears to occasionally flicker for a few ms before loading the content, I'm using:
router: {
scrollBehavior: function (to, from, savedPosition) {
return { x: 0, y: 0 }
}
}
This appears to be a common problem in Nuxt JS as it's of course not technically a page refresh, how could I go about fixing this?
Many Thanks.