Closed katerlouis closed 5 years ago
You need to use the appear prop for the animation to play initially
I didn't say anything about initial render is an issue- if you press the toggle button multiple times, the enter function of HelloWorld
still isn't called with Vue 2.6.10, as you can see in the provided demo. Please reopen the issue @posva
I have the same problem, and i down to 2.6.8 to get work.
the transition inside HelloWorld
needs the prop appear
to play at the same time as the parent appears:
<transition :css="false" @enter="enter" @leave="leave" appear>
<div class="hello">
For the leave transition it's currently not possible, you can track the feature at https://github.com/vuejs/vue/issues/9328
I hope this helps :)
Wait? Doesn't this also mean the HelloWorld component would animate / call the enter function on first load? I understand that this is the purpose of the appear
-prop. What if I don't want that?
And the leave transition isn't the issue here. It works as expected. Before the component dismounts, its leave
-function gets called.
I'm wondering why this change was introduced. We clearly lose functionality here.
@posva could you please look into this again? I'm still under the impression there is a misunderstanding here.
Again: leave
is not an issue.
And initial animation is not desired.
I still do not understand why the enter function should be called in this situation
// App.vue
<transition @enter="enter" @leave="leave" :css="false">
<img alt="Vue logo" src="./assets/logo.png" v-if="show">
</transition>
<HelloWorld msg="Helloooo" />
but not here
// HelloWorld.vue
<transition :css="false" @enter="enter" @leave="leave">
<div class="hello">
<h1>{{ msg }}</h1>
....
</div>
</transition>
It's hard to believe that this is intended. Could you please help me understand?
It is intended because the first one is wrapping an element with a v-if while the second isn't and it's directly there when the parent renders. So if you want it to apply the enter transition, you need the appear
prop
Okay, if I add appear
to the transition inside HelloWorld.vue
, its enter
-function rightfully/expectedly gets called when toggling. Cool.
But it also gets called on initial load of the app, which is not what I want and what I understand is exactly what appear
is there for.
How do you suggest working around that?
Because with this change, as is, I cannot update to the newer vue version in my app.
I read what you are saying, but still not fully understand what you are trying to solve with this new implementation. What was wrong with the way it worked before? Maybe an example would help illustrating the problem the old implementation caused.
The way it works now it the way it was always intended to work.
Bug Report: #9628 PR that fixed it: #9668
appear
, elements are not transitioned in on the first render of the <transition>
component(!), only on updates of the transition component (i.e. by switching a v-if inside of the <transition>
componentappear
, they are transitioned in on first render as well.But it also gets called on initial load of the app which is not what I want [...]
That could only be the case if the v-if="show"
in App.vue were also true when loading the app, which it isn't in your example.
So I assume it is (or can be) true at the initial load of your real app?
How do you suggest working around that?
I would handle this in a global fashion, i.e. set a (non-reactive) flag in the main component to true
after initial render.
Then each component can check that flag on re-render and determine wether or not appear
should be applied.
in App.vue
provide() {
return {
isFirstRender: () => { return this.isFirstRender === false }
}
},
updated() {
this.isFirstRender = false // do *not* add this prop to `data`!
}
in HelloWorld.vue
<template>
<transition
:appear="!isFirstRender()"
:css="false"
@enter="enter"
@leave="leave"
>
<div class="hello">
xxx
</div>
</transition>
</template>
<script>
import Vue from 'vue'
import { TweenMax } from 'gsap'
export default Vue.extend({
name: 'HelloWorld',
props: {
msg: String,
},
inject: ['isFirstRender'],
methods: {
enter(el, done) {
console.log('enter hello world called', el)
TweenMax.from(el, 2, { opacity: 0, xPercent: -100, onComplete: done })
},
leave(el, done) {
console.log('leave hello world called', el)
TweenMax.to(el, 2, { opacity: 0, xPercent: -100, onComplete: done })
},
},
})
</script>
I used provide/inject so this can be re-used in all of the app in different places that need this.
Other patterns, i.e. with HelloWorld accepting a prop, are also possible to imagine.
@LinusBorg I think I found a slight thought error in your code.
The pattern works really great, but on initial load your provided function, which asks "Am I the first render?!" returns false, since the flag is still undefined
and not false
yet;
So if I'm correct the pattern should look like this:
provide() {
return {
isFirstRender: () => { return this.isFirstRender === undefined }
}
},
updated() {
this.isFirstRender = false // do *not* add this prop to `data`!
}
Atleast that's how it worked for me; now !isFirstRender()
is false on first render, as expected;
[EDIT]
There's another issue I found with this pattern; you set the initalRender status only if some updated
fires, and that only that only happens when data changes. That's not always the case. So I had to do this.$forceUpdate()
in App.vue
s mounted()
.. or you could just set this.isFirstRender = false
in mounted()
..
Here's what I don't understand:
After doing this.isFirstRender = false
in App.vue
s mounted()
-hook, the slideOver component still doesn't slide on initial render (which is what I want ..) – but the App.vue mounts earlier than the slide component does, so why is this.isfirstRender
still undefined by that time?
[EDIT 2]
Why on earth is mounted()
of the SlideOver fired before Apps mounted()
?!
Version
2.6.10
Reproduction link
https://github.com/katerlouis/vue-2610-bug
Steps to reproduce
serve or build the app and press the toggle button
What is expected?
HelloWorld component should call
enter
functionWhat is actually happening?
HelloWorld component doesn't call
enter
functionenter
of the transition directly insideApp.vue
(the logo img) gets called though, which is odd. With vue v2.5.17 it works as expected (haven't used any other vue version since)