Vue: Transitioning children elements

Created on 18 Aug 2016  路  5Comments  路  Source: vuejs/vue

Vue.js version

1.0.26

Reproduction Link

http://jsfiddle.net/0gmusue5/

Steps to reproduce

  • Click on the button to open the slider (OK)
  • Click on the darkened zone on the left to close the slider (FAIL)
    -> The element is never removed. (We can't click on the body anymore, in that case)

    What is Expected?

The element should be removed after animation.

What is actually happening?

The element is not removed from the DOM. (afterLeave is never called)

More details

Note: I had to add the CSS transition: all 2s; to the class .slider-transition. Otherwise VueJS doesn't know about the transition time.

Improvement

I feel like the way I'm using the transition system is a bit "hacky" although I have no idea how to avoid it.
Ideally I'd like to be able to call transitions as follow:

<div id="slider" v-if="opened">
  <div id="slider-backdrop" @click="$emit('close')" transition="fade"></div>
  <div id="slider-content" transition="slide"></div>
</div>

But the transition attribute is only allowed at the v-if level.

Did I miss something ?
What do you think ?

Most helpful comment

Here is a "trick" I found to make it work : http://jsfiddle.net/0gmusue5/1/

The solution is still to add a false transition to the VueJS transitioned element and add a false attribute opacity: 0.999 to make it work (opacity: 1 doesn't work, I guess there needs to be a transition in a way). It still feels like a hack to me. Any advice or opinion about this ?

.slider-transition {
  transition: all 1s; // trick
  #slider-backdrop {
    transition: opacity .5s;
    opacity: .5;
  }
  #slider-content {
    transition: transform 1s;
    transform: translateX(36px);
  }
}

.slider-enter, .slider-leave {
  opacity: 0.999; // trick
  #slider-backdrop {
    opacity: 0;
  }
  #slider-content {
    transform: translateX(calc(100% + 36px));
  }
}

All 5 comments

Here is a "trick" I found to make it work : http://jsfiddle.net/0gmusue5/1/

The solution is still to add a false transition to the VueJS transitioned element and add a false attribute opacity: 0.999 to make it work (opacity: 1 doesn't work, I guess there needs to be a transition in a way). It still feels like a hack to me. Any advice or opinion about this ?

.slider-transition {
  transition: all 1s; // trick
  #slider-backdrop {
    transition: opacity .5s;
    opacity: .5;
  }
  #slider-content {
    transition: transform 1s;
    transform: translateX(36px);
  }
}

.slider-enter, .slider-leave {
  opacity: 0.999; // trick
  #slider-backdrop {
    opacity: 0;
  }
  #slider-content {
    transform: translateX(calc(100% + 36px));
  }
}

Yeah, I think there is no way for Vue to know which nested element to listen for transitionend event on, so it is listening only on the element the transition is on. Having fake "master transition" is the best workaround I can think of.

@simplesmiler That's why I asked for an improvement. It is definitely possible for Vue to get/cache the transitions that will happen at an element v-if or v-show. You just have to get all the elements below that have a transition attribute.

It's a bit easier using Vue2, though it still requires the top level element of the transition to know the max delay.

.slider-enter-active, .slider-leave-active {
  transition: all 1s; // trick
}

.slider-enter, .slider-leave-active {
  #slider-backdrop {
    opacity: 0;
  }
  #slider-content {
    transform: translateX(calc(100% + 36px));
  }
}

Demo : http://jsfiddle.net/0gmusue5/5/

This will be a wontfix in 1.x, and should be addressed in 2.x via the ability to explicitly declare transition durations (#4371)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

robertleeplummerjr picture robertleeplummerjr  路  3Comments

wufeng87 picture wufeng87  路  3Comments

hiendv picture hiendv  路  3Comments

loki0609 picture loki0609  路  3Comments

seemsindie picture seemsindie  路  3Comments