vue-router transitions with slide not scrolling to the top - vue.js

I use transitions in vue-router and it slides nice, but I would like to see the coming page from the top, instead, I need to scroll the new page manually to the top and this is not ok.
So I added the option scroll-behavior which should help me:
When using client-side routing, we may want to scroll to top when navigating to a new route, or preserve the scrolling position of history entries just like real page reload does. vue-router allows you to achieve these and even better, allows you to completely customize the scroll behavior on route navigation.
Here my configuration:
Router
const routers = [...]
const router = new VueRouter({
routes: routes,
mode: 'history',
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
//return savedPosition
return { x: 0, y: 0 } // just for debugging
} else {
return { x: 0, y: 0 }
}
}
});
App.vue
<template>
<div class="home">
<header-comp></header-comp>
<main>
<transition name="slide"
enter-active-class="animated slideInLeft faster"
leave-active-class="animated slideOutRight faster">
<router-view></router-view>
</transition>
</main>
<footer-comp></footer-comp>
</div>
</template>

Related

Vue Router scroll to id with extra space on top

In my Vue app, I have a fixed header of approximately 100px height.
I have a page where I have set an in page navigation to specific sections (= navigation to id's).
The navigation is working (when I click the anchor tag, it snaps to the correct section), but the top part of each section is always hidden underneath my header.
How can I set the scroll behavior of Vue Router, so the browsers scrolls to the section with for example 100px extra space on top?
Also, the 'smooth' behavior is not working either.
I have set my VueRouter as follows:
const router = new VueRouter({
routes,
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return {
selector: to.hash,
behavior: 'smooth',
x: 0,
y: 100,
};
} else {
return { x: 0, y: 0 };
}
},
});
My in page navigation is set as follows:
<div class="in-page-nav" v-if="applicationDetails">
<span>Shortcuts:</span>
<nav>
<router-link to="#application-details">Application details</router-link>
<router-link to="#application-answers">Application answers</router-link>
<router-link to="#jury-members">Jury members</router-link>
<router-link to="#jury-chats">Jury chats</router-link>
<router-link to="#applicant-chats">Applicant chats</router-link>
<router-link to="#voting-form" v-if="votingStatuses && openForVotes">
Make new vote</router-link>
<router-link to="#additional-info">Additional info</router-link>
<router-link to="#file-upload">Upload file</router-link>
<router-link to="#downloads" v-if="usrFileLink">Downloads</router-link>
</nav>
</div>

How to stop FOUC when leaving route with 'vue-flickity' carousel/slider?

I'm using the vue-flickity package for MetaFizzy's Flickity in my Vue app. When navigating away from a route that has an instance of vue-flickity slider, you get a brief FOUC showing all the slides unstyled in the document as the <Flickity /> slider is dismounted(?) and the view changes.
I've tried wrapping it in a <keep-alive>, but that doesn't help.
What would be the best approach to hiding or "animating out" the component before the user navigates away from a route?
I also tried to use beforeRouteLeave(), transition opacity on <Flickity ref="mySlider" /> to 0, then change route. I tried something like the following, but it didn't work as expected:
// SliderView.vue
<template>
<Flickity ref="mySlider">
<div v-for="(slide, index) in slides" :key="index">
// slide content markup
</div>
</Flickity>
</template>
<script>
import 'Flickity' from 'vue-flickity'
export default {
name: 'SliderView'
}
</script>
// router.js
import Vue from 'vue'
import Router from 'vue-router'
import SliderView from './views/SliderView.vue'
export default new Router({
routes: [
{
path: '/routeWithSlider',
component: SliderView,
beforeRouteLeave (to, from, next) {
const slider = this.$refs.mySlider
if (slider) {
slider.style.transition = 'opacity .5s'
slider.style.opacity = 0
setTimeout(() => {
next()
}, 600)
} else {
next()
}
}
}
]
})
Is this the correct approach, or should I be approaching this differently?
Also, if there was a way to do this globally for all <Flickity /> instances on all routes without specifying refs, that would also be useful too.
I haven't been using Vue for that long, so am looking for some guidance on the direction to take.
I found the best way to acheive this is to use BeforeRouteLeave() lifecycle hook on the component with the slider to animate the Flickity slider exit before changing route:
beforeRouteLeave (from, to, next) {
const slider = this.$refs.flickity.$el
slider.style.transition = 'opacity .25s ease'
slider.style.opacity = 0
setTimeout(() => {
next()
}, 250)
}

VueJS Router prevent back on certains router-link's

Building PWA app with VueJS and I have tabs like navigation component. But instead of show/hide content, navigation is done through Vue Router. Side effect of this navigation is "back" button behavior, every navigation action is logged in browser history, after I visit 4 tabs, and if I want to go back to actual page which was before page with tabs, I need to press "back" 4 or more times (depends on how many times I navigated trough tabs).
What I want to do is something like this:
<router-link no-history="true" to="tab1">Tab1</router-link>
<router-link no-history="true" to="tab2">Tab2</router-link>
<router-link no-history="true" to="tab3">Tab3</router-link>
Of course, I don't want to do it globally. If this even possible?
You need to use router.replace.
From Vue Documentation :
It acts like router.push, the only difference is that it navigates without pushing a new history entry, as its name suggests - it replaces the current entry.
In your case, you would just need to add the replace attribute to your router-link tag :
<router-link to="tab3" replace>Tab3</router-link>
You can find more informations about replace on Vue programmatic navigation doc
add replace to your router-link to avoid stacking routes on the navigation history :
Vue.config.productionTip = false;
Vue.config.devtools = false;
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<h5>Navigate between routes then click "previous"</h5>
<button #click="$router.go(-1)">Previous</button>
<p>
<router-link to="/foo" replace>Go to Foo</router-link>
<router-link to="/bar" replace>Go to Bar</router-link>
</p>
<router-view></router-view>
</div>

Keeping State of Vue

Is there a way to keep a state of a vue so that when navigated back it is shown?
Example:
1) I'm on Page A, search something, items are loaded, I scroll down and pick item 34 from the list.
2) Now Page B opens with information about the item. I click back but end on an empty Page A.
What I would want is the search results and ideally the scroll position from when I left that vue.
Is that possible out of the box in vue2 or do I have to code all of that myself?
So you want to somehow vuejs to remember to scrollPosition.As always that is very simple with vue.
The scroll behavior can managed by Vue-Router.I'll show you an example.
The Page component with 2 scroll positions
<template>
<div>
<div id="data1" style="height:700px;background:blue">
First scroll position
</div>
<div id="data2" style="height:700px;background:yellow">
Second scroll position
</div>
</div>
</template>
The component which navigate to page component
<template>
<div>
<router-link
tag="button"
:to="link"
>
Navigate to Page in scroll Position 2
</router-link>
</div>
</template>
<script>
export default {
data: () => ({
link: {
name: 'Page',
hash: '#data2' //<= important,this adds the #data2 in url
}
})
}
</script>
Now your route file have to look like this:
import Vue from 'vue'
import Router from 'vue-router'
import Page from '#/components/Page.vue'
import NavigationButton from '#/components/NavigationButton.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/Page',
name: 'Page',
component: Page,
},
{
path: '/',
name: 'NavigationButton',
component: NavigationButton
},
//other routes
],
mode: 'history',
scrollBehavior(to, from, savedPosition) {
if(savedPosition){ //when use press back button will go at the position he was on the page
return savedPosition
}
if(to.hash){ //if has a hash positition to go
return { selector: to.hash } //go to the page in scrolled Position
}
return { x:0, y: 0 } //go to the page in scroll = 0 Position
}
})
That i understood by your question,but i am not sure your asking about that.Anyway if i am right,dont forget also to take a look to official vue-router documentation about scroll behavior.See here

vuejs route between components scroll same

<template>
<div class="index">
<common-header id="common-header" class="common-header" v-el:commonheader></common-header>
<router-view transition keep-alive class="index-view"></router-view>
</div>
</template>
the route view will show two component A and B, while component A scrollTop is 0, I route to component B, and scroll down, and then route to component A, A is also scroll. Anyone have any ideas?
You can add a global before hook to the router, which will be called before every route transition starts and scroll to the top of the page. That is how I have solved it. Read here
Vue 1.
router.beforeEach(function (transition) {
window.scrollTo(0, 0)
transition.next()
})
For Vue2:
const router = new VueRouter({
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
})
Refer here
For Vuejs2.0, there is a new accepted way dealing with scroll behavior on page changes:
import VueRouter from 'vue-router';
const router = new VueRouter({
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
})
This will scroll to the top of the page after each navigation change. You can read up on the full, official documentation about this functionality here.
I think you are scroll the wrong element.I have make the same mistake like that:component A and component B is both in element Body,and I make the body scroll,so as long as you move the scroll bar,it will work for both A&B.I finally work out it by scrolling component instead of scrolling the body.