Vue Transition inside the div element doesn't work - vue.js

Could someone explain me, why the following code doesn't work?
<template>
<div class="modal">
<transition name="slide-in">
<div #click.stop class="modal__container">
<div #click="close" class="modal__button">
<span class="modal__button--close">Close</span>
</div>
</div>
</transition>
<transition name="fade-in">
<div #click="close" class="modal__overlay"/>
</transition>
</div>
</template>
I'm trying to create modal with two different animations (slide-in for text area and fade-in for modal overlay).
If i delete the element with class modal and edit code to the following everything works fine.
<template>
<transition name="slide-in">
<div #click.stop class="modal__container">
<div #click="close" class="modal__button">
<span class="modal__button--close">Close</span>
</div>
</div>
</transition>
</template>

Referencing Vue.js documentation on transitions
Vue provides a variety of ways to apply transition effects when items are inserted, updated, or removed from the DOM
That means that DOM nodes that transition applies classes to, should be those which are inserted/updated/removed.
Since it is a modal window, I assume that it has v-if directive applied in parent component to handle it's visibility. In order for transition to work, it should wrap DOM element that will be updated.
You can understand it more easily if you move code of your modal window into the parent component. Just for better visualization of elements tree and transition's behavior.
In first example, conditional rendering (v-if) applies to <div class="modal">, which is not wrapped with transition - therefore no animation will be triggered. At the same time, nested nodes are wrapped with transition, but there is nothing that will update or remove them. They are statically displayed and inserted initially on component's creation. Nothing to animate.
In order for it to work as expected following structure would be advisable:
<template>
<transition name="fade-in">
<div
class="modal__overlay"
#click="close"
>
<transition name="slide-in">
<div
v-if="containerVisible"
class="modal__container"
#click.stop
>
<div #click="close" class="modal__button">
<span class="modal__button--close">Close</span>
</div>
</div>
</transition>
</div>
</transition>
</template>
This solution expects modal__overlay to have position: fixed; style and variable containerVisible to be set to true inside mounted hook of modal component.

Related

Why is my transition not working on "leave"?

I have a global confirmModal.vue which looks like this:
<template>
<Transition
appear
enter-from-class="opacity-0"
enter-to-class="opacity-100"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
>
<div
#click="$emit('cancel')"
class="bg-black/50 z-50 fixed inset-0 flex justify-center items-center transition duration-300 ease-in-out p-8 cursor-pointer"
>
<Transition appear enter-from-class="scale-50" enter-to-class="scale-100">
<div
#click.stop
class="flex flex-col gap-4 shadow-2xl p-8 rounded min-w-[300px] max-w-[480px] bg-lf-white transition duration-300 ease-in-out cursor-auto"
>
<h3 class="font-medium text-2xl">{{ title }}</h3>
<p>{{ text }}</p>
<div class="flex justify-end gap-2">
<Button #click="$emit('cancel')" variant="white">Annuler</Button>
<Button #click="$emit('confirm')">Supprimer</Button>
</div>
</div>
</Transition>
</div>
</Transition>
</template>
The first transition adds a fade in effect to the backdrop while the nested transition adds a smooth apparition effect for the modal itself.
It works fine but what I don't understand is that when I close the modal, the leave part of the transition does not trigger at all.
This is what the component calling this modal looks like:
<ConfirmModal
v-if="showConfirmModal"
title="Suppression"
text="Êtes-vous sûr de vouloir supprimer cet article ?"
#cancel="handleHideConfirmModal"
#confirm="handleConfirmAction"
/>
Here's a gif of what it's currently looks like:
EDIT: I achieved the wanted result by wrapping ConfirmModal.vue with Transition from the parent component, like this:
<Transition
enter-from-class="opacity-0"
enter-to-class="opacity-100"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
>
<ConfirmModal
v-if="showConfirmModal"
title="Suppression"
text="Êtes-vous sûr de vouloir supprimer cet article ?"
#cancel="handleHideConfirmModal"
/>
</Transition>
I don't understand why I have to do this and why in this exemple the person doesn't need to do that though, they use Transition from inside the child component and the transition works fine
It's also not ideal because every time I use this component I will have to think to wrap it inside this transition for it to fully work
It's probably caused by the use of different versions of Vue.
Your question is tagged vuejs3, so you are very likely using Vue 3, but, in the example you linked, vue version 2.6.4 is being used.
In vue 3, at least, you must use the directives v-if or v-show in the root element inside the Transition component for it to trigger the changes whenever the root component inside appears and disappears.
you can read more about transitions here

VueJS transition on computed values

I want to animate a block with posts that can be filtered.
Some filters trigger a computed method filteredPosts and they are assigned to a component liek that <block-article :posts="filteredPosts" />
In my <block-article> component I have something like that :
<template>
<div class="posts">
<div v-for="post in posts" :key="post.id"></div>
</div>
</template>
I want div .posts animate like a translation bottom/fade out on disappear and translation top/ fade in on appear.
I tried that :
<template>
<transition name="slide-fade">
<div class="posts">
<div v-for="post in posts" :key="post.id"></div>
</div>
</transition>
</template>
with corresponding css classes but it doesn't work.
I tried that :
<template>
<div class="posts">
<transition-group name="slide-fade">
<div v-for="post in posts" :key="post.id"></div>
</transition-group>
</div>
</template>
but my class .posts is a grid and here I lost the grid behavior.
THE AIM is to animate the entire div .posts rather than each elements of the v-for.
Any idea ?
Thanks all,
I finally achieve this with :
<transition name="slide-fade">
<div :key="posts.length" class="posts"></div>
</transition>
Nothe the :key="posts.length"
The problem is when posts.length doesn't change but it works in a lots of case. I will search how to fix this exception.
If you animate entire div, you should use transition, but in this case all inner elements not animated. If you want to animate all inner elements. You should use transition-group
In your case I think, need use all this method with build-in tag attribute.
Becouse in dock you can read
https://v2.vuejs.org/v2/guide/transitions.html
Unlike transition, it renders an actual element: a span by default. You can change the element that’s rendered with the tag attribute.
So you can write like this(its not full code, you must add name, key and other attrs)
<transition>
<transition-group tag="div" class="posts">
<div v-for="post in posts"></div>
</transition-group>
</transition>

how to make modal movable from one end to other end using vue js

Have code like this in vue.js ,my agenda is to make the modal movable from one end to other end, here is my code,have used bootstrap modal for this purpose and have included : draggable
<b-modal ref="my-modal" hide-footer title="Edit Record">
<div class="card">
<div class="card-header d-flex justify-content-between">
<div class="">Viz Attributes</div>
</div>
<div class="card-body">
</div>
</div>
</b-modal>
you can't position them absolutely in the viewport.
You would need to change the positioning of the modal dialog sub-container to absolute and control the left/top position based on dragging. This is not an overly easy task. You would need to create your own modal to draggable.
I suggest to you use Vue.js modal component DEMO: www.vue-js-modal.yev.io
install: www.npmjs.com/package/vue-js-modal
<modal name="bar" draggable=".window-header">
<div class="window-header">DRAG ME HERE</div>
<div>
Hello!
</div>
</modal>
Draggable property can accept not only Boolean but also String parameters.

Vue v-if destroys scrollbar plugin

I try to use custom scrollbar using vuebar on dynamic Vue elements. Since v-if destroys and recreates elements, vuebar is not activated after that. On example provided you can see scrollbar works till you change tabs. I know you can use v-show and it starts working, but that solution is impossible to implement in nested components with complicated relations.
<div class="vuebar-element" v-bar v-if="tab==0">
<div>
tab 0
</div>
</div>
<div class="vuebar-element" v-bar v-if="tab==1">
<div>
tab 1
</div>
</div>
http://jsfiddle.net/ebwdnqfs/2/
After reading comment from #ssc-hrep3 I discovered that putting whole thing into
< transition > tag magically solves the problem.
<transition>
<div class="vuebar-element" v-bar v-if="tab==0">
<div>
tab 0
</div>
</div>
<div class="vuebar-element" v-bar v-if="tab==1">
<div>
tab 1
</div>
</div>
</transition>

Vuejs transition 1 pager for components

I have 1 page with 2 components. Component A has a button, when clicking disalbe A and show component B.
If i use transition i am getting this error.
I want a nice fadeout A and fade in B, how can i achieve?
Error:
[Vue warn]: <transition> can only be used on a single element. Use <transition-group> for lists.
App.js
<transition name="fade">
<div class="fade-enter-active" v-show="datatable">
<component-a :title="'AAA'"></component-a>
<button v-on:click="showCompB">Show B and disable A</button>
</div>
<div class="fade-enter-active" v-show="componentb">
<component-b :title="'BBB'"></component-b>
</div>
</transition>
export default {
data() {
return {
datatable: true,
componentb: false,
etc etc
Good morning sir,
As the error stated, the <transition> component can be used only with a single child element. You can learn more about that here: https://v2.vuejs.org/v2/guide/transitions.html
You could instead use two <transition> components to handle the fade animation for each one of your elements like so:
<transition name="fade">
<div v-show="datatable">
<component-a :title="'AAA'"></component-a>
<button v-on:click="showCompB">Show B and disable A</button>
</div>
</transition>
<transition name="fade">
<div v-show="componentb">
<component-b :title="'BBB'"></component-b>
</div>
</transition>
The fade animation will be applied to each div whenever componentb and datatable is visible or not.
Hope that helps you.