'Vue2 v-if is making my transition not work

I've currently got a v-if directive on an element that is meant to be a lightbox to display a shopping cart.

With a click on a "View Cart" button on my navbar, the state of the lightbox will activate the v-if statement.

All that works fine, but ive also tried to toggle an additional class to the lightbox element called "visible" and that will activate a transition on the opacity to give a fade-in/out effect.

However, what I'm currently getting is the v-if makes my lightbox cart appear instantaneously. Is there a way to make my transition work with the v-if?

Here is my code below:

<template>
    <div class="full-page">
        <navbar @openCart="toggleCart"/>
        <product />
        <div class="lightbox"
            v-if="lightboxCart"
            :class="{visible: lightboxCart}">
            <cart
                @closeCart="toggleCart"/>
        </div>
    </div>
</template>

<script>
export default {
    head() {
        return {
            title: 'Totonou',
            meta: [
                {
                    hid: 'description',
                name: 'description',
                content: 'Customizable Jewelry Organizer'
                }
            ]
        }
    },
    data() {
        return {
            lightboxCart: false
        }
    },
    components: {
        'navbar' : require('@/components/AppHeader.vue').default,
        'product' : require('@/components/ProductPage/Product.vue').default,
        'cart' : require('@/components/CartPage/Cart.vue').default,
    },
    methods: {
        toggleCart() {
            this.lightboxCart = !this.lightboxCart
        }
    }
}
</script>

<style scoped>
    .fullpage {
        position: relative;
    }
    .lightbox {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background-color: rgba(0,0,0,0.5);
        width: 100%;
        height: 100%;
        opacity: 0;
        transition: 0.8s all cubic-bezier(0.39, 0.575, 0.565, 1);
    }
    .lightbox.visible {
        opacity: 1;
    }

</style>


Solution 1:[1]

You can use vue transitions:

new Vue({
  el: "#demo",
  data() {
    return {
      lightboxCart: false
    }
  },
  methods: {
    toggleCart() {
      this.lightboxCart = !this.lightboxCart
    }
  }
})
.fullpage {
    position: relative;
}
.lightbox {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: rgba(0,0,0,0.5);
    width: 100%;
    height: 100%;
    /* opacity: 0; */
    transition: 1.8s all cubic-bezier(0.39, 0.575, 0.565, 1);
}
.lightbox.visible {
  /* opacity: 1; */
}
.fade-enter-active, .fade-leave-active {
  transition: opacity 1.5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
  <div class="full-page">
    <button @click="toggleCart">show</button>
    <transition name="fade">
      <div class="lightbox"
          v-if="lightboxCart"
          :class="{visible: lightboxCart}">
      </div>
    </transition>
  </div>
</div>

Solution 2:[2]

Css transitions would not work with v-if, because it's not just changing the element visibility, but completely removes it from the dom. You can use Vue transitions; Here's the code:

<transition name="fade">
  <div
    class="lightbox"
    v-if="lightboxCart"
    :class="{visible: lightboxCart}"
  >
     <cart @closeCart="toggleCart"/>
  </div>
</transition>

You should also add the css classes related to this transition:

.fade-enter-active, .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}

I've used the fade transition here, but you can choose other transitions, or create your own transition. Here is the related link:

Vue Transitions

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nikola Pavicevic
Solution 2