I have two components, CommentList, and CommentItem. Every comment can have replies, so it is recursive.
Here are their templates:
CommentList:
<template>
<!-- other code -->
<transition name="fade-list" mode="out-in">
<transition-group
v-if="comments.length"
name="fade"
tag="ul"
appear
>
<CommentItem
v-for="(comment, index) in comments"
:key="comment.id"
:comment="comment"
/>
</transition-group>
</transition>
<!-- other code -->
</template>
CommentItem:
<template>
<li>
<!-- other code -->
<transition name="fade-list" mode="out-in">
<transition-group
v-if="comment.replies"
name="fade"
tag="ul"
appear
>
<CommentItem
v-for="reply in comment.replies"
:key="reply.id"
:comment="reply"
/>
</transition-group>
</transition>
<!-- other code -->
</li>
</template>
import CommentListTransition from './CommentListTransition.vue';
export default {
components: {
CommentListTransition,
},
}
In such case all works. But then I decided to move the transition block to a separate component and the comment replies stopped showing:
CommentList:
<template>
<!-- other code -->
<CommentListTransition
:comments="comments"
/>
<!-- other code -->
</template>
CommentItem:
<template>
<li>
<!-- other code -->
<CommentListTransition
v-if="comments.replies"
:comments="comments.replies"
/>
<!-- other code -->
</li>
</template>
import CommentListTransition from './CommentListTransition.vue';
export default {
name: 'CommentItem',
components: {
CommentListTransition,
},
props: {
comment: {
type: Object,
required: true,
},
},
}
CommentListTransition:
<template>
<transition name="fade-list" mode="out-in">
<transition-group v-if="comments.length" name="fade" tag="ul" appear>
<CommentItem
v-for="(comment, index) in comments"
:key="comment.id"
:comment="comment"
/>
</transition-group>
</transition>
</template>
<script>
import CommentItem from './CommentItem.vue';
export default {
components: {
CommentItem,
},
props: {
comments: {
type: Array,
default: () => [],
},
},
};
</script>
<style>
.fade-enter-active,
.fade-move {
transition: 0.4s ease all;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: scale(0.6);
}
.fade-leave-active {
transition: 0.4s ease all;
position: absolute;
}
.fade-list-enter-active,
.fade-list-leave-active {
transition: 0.4s ease all;
}
.fade-list-enter-from,
.fade-list-leave-to {
transform: translateY(10px);
opacity: 0;
}
</style>
Of course this can be implemented via slot
:
<template>
<transition name="fade-list" mode="out-in">
<transition-group name="fade" tag="ul">
<slot></slot>
</transition>
</template>
But I would like to call CommentItem inside CommentListTransition.
How can this be fixed?
I tried to put transition, and transition-group with comments in a separate component, but the child comments stopped displaying.
I want all comments to be displayed, both parent and child comments.
I tried your code and the only thing I change is displayed Comments
and your animation works fine. (I passed your components in Composition Api
It wasn't working in Options
→ Component used before initialization
)
The object I use in App.vue
I hope it's the good form you want or the comments object
<script setup lang="ts">
import CommentList from './CommentList.vue';
let id = 0;
const comments = [
{ id: id++, comment: 'test', replies: [{ id: id++, comment: 'test2' }] },
{
id: id++,
comment: 'test3',
replies: [
{
id: id++,
comment: 'test4',
replies: [
{ id: id++, comment: 'test5' },
{ id: id++, comment: 'test6' },
],
},
],
},
];
</script>
<template>
<CommentList :comments="comments" />
</template>
CommentList.vue
<template>
<!-- other code -->
<CommentListTransition :comments="comments" />
<!-- other code -->
</template>
<script setup lang="ts">
import CommentListTransition from './CommentListTransition.vue';
defineProps<{
comments: any[];
}>();
</script>
CommentListTransition.vue
<template>
<Transition
name="fade-list"
mode="out-in"
>
<TransitionGroup
v-if="comments.length"
name="fade"
tag="ul"
appear
>
<CommentItem
v-for="comment in comments"
:key="comment.id"
:comment="comment"
/>
</TransitionGroup>
</Transition>
</template>
<script setup lang="ts">
import CommentItem from './CommentItem.vue';
defineProps<{
comments: any[];
}>();
</script>
<style>
.fade-enter-active,
.fade-move {
transition: 0.4s ease all;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: scale(0.6);
}
.fade-leave-active {
transition: 0.4s ease all;
position: absolute;
}
.fade-list-enter-active,
.fade-list-leave-active {
transition: 0.4s ease all;
}
.fade-list-enter-from,
.fade-list-leave-to {
transform: translateY(10px);
opacity: 0;
}
</style>
CommentItem.vue
<template>
<li>
<!-- other code -->
<p>{{ comment.comment }}</p>
<CommentListTransition
v-if="comment.replies"
:comments="comment.replies"
/>
<!-- other code -->
</li>
</template>
<script setup lang="ts">
import CommentListTransition from './CommentListTransition.vue';
defineProps<{
comment: any;
}>();
</script>
With this code, all comments are displayed, and I got the transition on each. Are you sure you assign a valid ID to your comment ? Hope it helps you :).