Randy Hall
Randy Hall

Reputation: 8137

Vue add class before insert, leave it

I have a custom animation that the regular Vue transition doesn't quite cover. I have it implemented elsewhere with a conditional v-bind:class, but that doesn't work well for conditional v-if blocks or v-for groups.

I need to add a class ('open') one frame after the element is entered as with v-enter-to, but I need it to never be removed from the element.

I then need it removed removed when leaving to trigger the closing animation.

Am I using Vue Transition wrong and this is perfectly possible within transition, or is there a way to add/remove the class around the enter/leave functionality?

.accordion {
    overflow: hidden;

    > div {
        margin-bottom: -1000px;
        transition: margin-bottom .3s cubic-bezier(.5,0,.9,.8),visibility 0s .3s,max-height 0s .3s;
        max-height: 0;
        overflow: hidden;
    }

    &::after {
        content: "";
        height: 0;
        transition: height .3s cubic-bezier(.67,.9,.76,.37);
        max-height: 35px;
    }

    &.open {
        max-height: 8000px;

        > div {
            transition: margin-bottom .3s cubic-bezier(.24,.98,.26,.99);
            margin-bottom: 0;
            max-height: 100000000px;
            position: relative;
        }

        &::after {
            height: 35px;
            max-height: 0;
            transition: height .3s cubic-bezier(.76,.37,.67,.9),max-height 0s .3s;
        }
    }
}
<transition name="accordion" :duration="300">
  <div class="accordion" v-if="equipmentSelections.length === 0">
    <div>
      <p>Begin by selecting equipment from the list</p>
    </div>
  </div>
 </transition>
 
<transition-group name="accordion" :duration="300">
  <div v-for="equipment in equipmentSelections" v-bind:key="equipment.unitNumber" class="accordion">
    <div>
      <h3 v-on:click="updateSelections(equipment)">{{equipment.unitNumber}}</h3>
    </div>
  </div>
</transition-group>

Upvotes: 1

Views: 987

Answers (1)

RoboKozo
RoboKozo

Reputation: 5062

You can get more power out of the vue transition component by using the javascript hooks.

For example: Demo: https://codepen.io/KingKozo/pen/QWpBPza

HTML:

<div id="app">
  <div>
    <button type="button" @click="toggle">Toggle</button>
  </div>
  <transition name="label" v-on:enter="enter" v-on:before-leave="leave">
    <div v-if="isOpen">Hi</div>
  </transition>
</div>

CSS

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

.staying-visible {
  background-color: red;
  color: white;
}

Javascript

const vm = new Vue({
  el: '#app',
  data: {
    isOpen: false
  },
  methods: {
    enter(el){
      el.classList.add("staying-visible")
    },
    leave(el){
      el.classList.remove("staying-visible")
    },
    toggle(){
      this.isOpen = !this.isOpen
    }
  }
})

In the example I provided I add a brand new class, "staying-visible", to the element on enter and remove it later on. In the example provided, I remove the class on "before-leave" so as to make the change visible but for your specific use case it seems like you can also just remove it during the 'leave' hook.

To learn more about how to use the javascript transition hooks, check out the official documentation: https://v2.vuejs.org/v2/guide/transitions.html#JavaScript-Hooks

Upvotes: 3

Related Questions