drake035
drake035

Reputation: 2897

Can't change transition on the fly for a transition group

In my app, clicking a modal's close button makes it disappear with a fade animation whereas swiping it down makes it disappear with a swipe animation. This is done by changing the modal's <transition name> based on event.

The same thing doesn't seem to work with a transition group. Am I doing something wrong, or is it actually not possible?

CodeSandbox

Template:

<transition-group :name="itemTransition">
  <div
    v-for="item in items"
    :key="item.id"
    v-hammer:swipe.up="() => onSwipeUp(notification.id)"
  >
  </div>
</transition-group>

Script:

export default {
  data () {
    return {
      applySwipeTransition: false
    }
  },
  computed: {
    itemTransition () {
      return this.applySwipeTransition ? 'swipe' : 'fade'
    }
  },
  methods: {
    onSwipeUp (id) {
      this.applySwipeTransition = true
      this.$nextTick(() => {
        this.closeItem(id)
        this.applySwipeTransition = false
      })
    }
  }
}

CSS:

.fade-leave-active {
  animation: fade-out .75s;
}

.swipe-leave-active {
  animation: slide-up .25s;
}

Upvotes: 3

Views: 793

Answers (2)

Igor Moraru
Igor Moraru

Reputation: 7729

The problem lies in the timing of component update. You are switching the transition mode back to fade in the same update cycle as when the element is closed. Thus, when the next component update is triggered (by removal of the item), the transition is already switched back to fade. At this point, you may have guessed that all that needs to be done, is to switch the transition back in the next update, triggered by removal of the item:

   onSwipeUp (id) {
     this.applySwipeTransition = true
     this.$nextTick(() => {
        this.closeItem(id)
        this.$nextTick(()=>{
          this.applySwipeTransition = false
        })         
     })
   }

Since there are no reasons to wait for component update to close the item, you can simplify the code a bit:

   onSwipeUp (id) {
      this.applySwipeTransition = true
      this.closeItem(id)
      this.$nextTick(() => {
        this.applySwipeTransition = false
      })
    }

Here is your working sandbox: https://codesandbox.io/s/vue-template-forked-60lkk?file=/src/App.vue

Upvotes: 3

MT_dev
MT_dev

Reputation: 163

So, I've worked around with your CSS by manually changing the name of the <transition-group to either fade or swipe to see if the there's a problem with the CSS animations.

Verdict: The fade works. swipe only transitions the list-item off the page by a click and drag, not true swipe, if that concerns you (by the way, my swipe is MacOS swipe - two-finger, no click)

Still, without changing the CodePen, the issue seems to be with your computed property where there's nothing telling the name to change dynamically even though you've bound it to a computed property - the logic for itemTransition() seems to always default to fade because the applySwipeTransition would never equal to "swipe", given that the CSS does work when you manually change name to swipe (see "Verdict)".

To see where the underlying issue was, I worked around with your itemTransition():

computed: {
    itemTransition() {
      return this.applySwipeTransition ? "fade" : "swipe";
    },

Switching the order of the fade and swipe now makes swipe work. I hope this gives you some insight into the issue. You may need to create a custom Vue directive or event to handle the swipe / fade logic if needed.

Upvotes: 0

Related Questions