If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeWhen we click the button, I want to also transition the title. Right now, it changes instantly, which is not that big of a deal... but we can do better. Back at your editor, find the <title
component and wrap it in a transition
. Copy the name
and mode
from earlier and use those here too.
<template> | |
<div :class="[$style.component, 'container-fluid']"> | |
<div class="row"> | |
... lines 4 - 18 | |
<div class="col-xs-12 col-lg-9"> | |
<transition | |
name="fade" | |
mode="out-in" | |
> | |
<title-component :text="pageTitle" /> | |
</transition> | |
... lines 26 - 59 | |
</div> | |
</div> | |
</div> | |
</template> | |
... lines 64 - 180 |
So the big question is: does this work? Are we allowed to transition a prop change? In this case, we're not hiding and showing a component, we're just changing the value passed to the text
prop.
The answer is... sort of. If you try it right now - I'll close my dev tools so we can see things - it does not work. Well, the title did change, but it still changes instantly: there's no transition.
The truth is that there is no built-in way for Vue to transition a prop change. And... that makes sense! All Vue knows how to do is add some classes when an entire element or component is being hidden or shown. A prop change is much more complex than that: who knows how we might be using it!
Vue does have documentation about how you can add transitions for a prop change, but mostly, you're doing it manually on a case-by-case basis.
However, it is possible to, sort of, make this work. Over on the title
component, add a new key
prop. Yea, that's the prop we normally use in loops. Set this to something that will be unique for each title, like currentState
, because we know the page title is based on the currentState
.
<template> | |
<div :class="[$style.component, 'container-fluid']"> | |
<div class="row"> | |
... lines 4 - 18 | |
<div class="col-xs-12 col-lg-9"> | |
<transition | |
name="fade" | |
mode="out-in" | |
> | |
<title-component | |
:key="currentState" | |
:text="pageTitle" | |
/> | |
</transition> | |
... lines 29 - 62 | |
</div> | |
</div> | |
</div> | |
</template> | |
... lines 67 - 183 |
Move over and try it now. Ah! It works! The title fades out and fades in just like the rest of the page!
So... how and why did that work? Especially right after I explained to you that you can't transition prop changes!
When we click the button, our top-level component re-renders and the title
component now has a new value for its key
prop. That actually tells Vue that the new title
component should be a totally different instance than the one it was using before.
In other words, instead of re-rendering the same component instance... but passing in a new text
prop, Vue completely destroys the old title
component and creates a brand new one. This allows Vue to transition between the old and new title because the old component is hidden and the new component is shown.
This works great in our case... but it's kind of a "nuclear" option. If our title
component had some data inside of it, that data would be completely lost each time we switched... because we're destroying and recreating the component. So it might work in some cases... but not in others.
For us, I'm super happy with this. So next: let's add a form to the checkout page!
"Houston: no signs of life"
Start the conversation!
// package.json
{
"devDependencies": {
"@fortawesome/fontawesome-free": "^5.15.1", // 5.15.1
"@symfony/webpack-encore": "^0.30.0", // 0.30.2
"axios": "^0.19.2", // 0.19.2
"bootstrap": "^4.4.1", // 4.5.3
"core-js": "^3.0.0", // 3.6.5
"eslint": "^6.7.2", // 6.8.0
"eslint-config-airbnb-base": "^14.0.0", // 14.2.0
"eslint-plugin-import": "^2.19.1", // 2.22.1
"eslint-plugin-vue": "^6.0.1", // 6.2.2
"regenerator-runtime": "^0.13.2", // 0.13.7
"sass": "^1.29.0", // 1.29.0
"sass-loader": "^8.0.0", // 8.0.2
"vue": "^2.6.11", // 2.6.12
"vue-loader": "^15.9.1", // 15.9.4
"vue-template-compiler": "^2.6.11", // 2.6.12
"webpack-notifier": "^1.6.0" // 1.8.0
}
}