I am currently facing an issue where the <keep-alive> stops working after adding a :key to the parent <div>. This <div> and also the :key is needed, otherwise the <transition> won't work. Anyone got a solution for that?
Sorry i am not able to provide more code.
<template>
<router-view v-slot="{ Component, route }">
<transition :name="transitionName">
<div :key="route.name">
<keep-alive include="SpecialComponent">
<component :is="Component" />
</keep-alive>
</div>
</transition>
</router-view>
</template>
It looks like even putting you component in a div alone prevents transitions.
My test app components inside a div didn't do any transitions even if I don't use <keep-alive> and :key.
Why do you need to wrap it in a div?
Shouldn't it work so?
<transition :name="transitionName">
<keep-alive include="SpecialComponent">
<component :is="Component" :key="route.name" />
</keep-alive>
</transition>
I have a wrapper component with a transition:
// Wrapper.vue
<template>
<transition
appear
mode="out-in"
enter-active-class="animate__animated animate__fadeIn animate__faster"
leave-active-class="animate__animated animate__fadeOut animate__faster"
>
<div :key="$route.path">
<slot />
</div>
</transition>
</template>
Then, I populate the default slot with some component from router as follows:
// Page.vue
<template>
<Wrapper>
<router-view v-slot="{ Component }">
<component :is="Component" />
</router-view>
</Wrapper>
</template
And I'm getting
[Vue Router warn]: <router-view> can no longer be used directly inside <transition> or <keep-alive>. warnings, which seems weird since I'm using the correct syntax imho. Is this intended and if so, what am I missing?
Note: It works properly, I just don't like looking at warnings :)
EDIT: A bit more context - I'm trying to create wrappers for desktop and mobile devices while desktop devices should have the transition described above. The mobile device wrapper is done quite differently and is not relevant here.
The warning is not supposed to display in this scenario, but only when the "router-view" is the direct child of a "transition" or "keep-alive" component.
The bug has been reported here: https://github.com/vuejs/router/issues/1306
By official guide you should use <transition> or <keep-alive> inside <RouterView /> and vice-versa not applicable.
<router-view v-slot="{ Component, route }">
<transition name="fade">
<component :is="Component" :key="route.path" />
</transition>
</router-view>
<router-view> exposes a v-slot API mainly to wrap your route components with <transition>, <keep-alive> components.
update:
A computed property may be helpful for this scenario. Tough, I don't know how you've implemented code for small devices. This is one way of doing...
<script>
function isSmallDevice() {
/*
code for checking
device resolution
*/
return <Boolean>
}
export default {
computed: {
setTransitionProperty: function () {
return isSmallDevice ? '' : 'fade'
}
}
}
</script>
<router-view v-slot="{ Component, route }">
<transition :name="setTransitionProperty" mode="out-in">
<template #default>
<component
:is="Component"
:key="route.meta.usePathKey ? route.path : undefined"
/>
</template>
<template #fallback> Loading... </template>
</transition>
</router-view>
Another way may be conditional rendering, using v-if, and v-else directives.
App.vue has a transition tag to fade the pages out and in.
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in" appear>
<component :is="Component"></component>
</transition>
</router-view>
The Page.vue file has a simple structure, however, it also has a basic sliderjs component which throws the error <Transition> renders non-element root node that cannot be animated. If the transition tag is removed, everything works fine.
<div v-if="page.isReady">
<swiper>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
</swiper>
</div>
https://swiperjs.com/vue/
The file also has the following:
import { Swiper, SwiperSlide } from 'swiper/vue';
import 'swiper/swiper.scss';
export default {
components: {
Swiper,
SwiperSlide,
},
setup () {
return {
page: usePage()
}
}
}
Is there any trick to fix the error? Thanks for any tips!
No.
<template>
<div></div>
<div>~someone~</div>
</template>
Yes.
<template>
<div>
<div></div>
~someone~
</div>
</template>
If you do not use a "div" tag just inside the "Template" tag, you will get the same error. (By the way, it was possible to use other than div tags)
Transitions require single children nodes. Therefore you can wrap the <component> tag inside a <div>, however, a plain <div> inside a <transition> won't trigger the transition, but changing the key attribute does.
We can obtain a unique key by getting the route name:
<router-view v-slot="{ Component, route }">
<transition name="fade" mode="out-in">
<div :key="route.name">
<component :is="Component"></component>
</div>
</transition>
</router-view>
This will effectively transition between routes with a different name, but if you also want to transition between routes of the same name with different parameters, you can use route.fullPath instead of route.name as the key.
I can't fully take credit for this one...but I was having a similar issue and the problem was I had multiple nodes in my view, and found this guy's post on the Vue.js forums:
Found my mistake too. Transition required a single root in components! Since Vue 3 no longer requires a single root node for components I thought this also applies to transitions.
But it’s also logical. CSS requires a single root to which the transitions can refer.
When toggling between elements that have the same tag name, you must tell Vue that they are distinct elements by giving them unique key attributes. Otherwise, Vue’s compiler will only replace the content of the element for efficiency. Even when technically unnecessary though, it’s considered good practice to always key multiple items within a component.
<div>
<router-link to="/"></router-link>
<router-link to="/about"></router-link>
</div>
<router-view v-slot="{ Component, route }">
<transition name="route" :key="route" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
I solved it, it was a minor mistake, there was a character outside a html tag, directly after the tag (comma).
<template>,
<div>
<div>
<swiper>
<swiper-slide>Slide 1</swiper-slide>
<swiper-slide>Slide 2</swiper-slide>
<swiper-slide>Slide 3</swiper-slide>
</swiper>
</div>
</div>
</template>
your dynamic component instance must have a root element.
in you example,'Swiper' and 'SwiperSlide' must have a root element!
don't use RouterView in component parameter of the router. if you need to do that put it inside a root element
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in" appear>
<!-- root element -->
<div>
<component :is="Component"></component>
</div>
</transition>
</router-view>
A solution that worked for me using Nuxt3:
Parent page was:
<template>
<NuxtPage />
</template>
but should be also wrapped into a root node:
<template>
<div>
<NuxtPage />
</div>
</template>
Otherwise I got a transition exception:
Component inside <Transition> renders non-element root node that cannot be animated
I'm doing like this and it works.
<template>
<router-view v-slot="slotProps">
<transition name="route" mode="out-in">
<component :is="slotProps.Component"></component>
</transition>
</router-view>
</template>
Here is code example:
https://jsfiddle.net/9jypnkue/
The transition v-on:enter="enter" for the nested view is not called when also the main router-view is transitioning.
<router-view ref="nestedView" v-slot="{ Component }">
<transition v-on:enter="enter">
<component :is="Component"/>
</transition>
</router-view>
I would like both animations being called simultaneously.
Using Vue 3 and Vue Router 4 release candidate/beta.
Adding 'appear' to the router fixes it:
<router-view ref="nestedView" v-slot="{ Component }" appear>
<transition v-on:enter="enter">
<component :is="Component"/>
</transition>
</router-view>
https://jsfiddle.net/27qae5zj/1/
I have a global sidebar component TheSidebar.vue:
<template>
<aside>
<slot></slot>
</aside>
</template>
In Blogs.vue (a page component) I try to register two components.
<template>
<div>
<h1>Experiences</h1>
<TheSidebar>
<SearchBlog />
<CategoryCheckboxFilter />
</TheSidebar>
<ExperienceList />
</div>
</template>
It seems like I cannot register two components in a slot?
Is this a good setup anyway and who do I have to achieve this?
Update
It's just working fine now and I can register more than one component in a <slot />. I think some webpack building issue before.