Animating children
Traditionally, coordinating animation across multiple children has been an involved process.
With Pose for Vue, it’s as simple as animating just one. It looks like this:
const Component = {
components: {
Parent: posed.ul(ulPoses),
Child: posed.li(liPoses)
},
template: `
<Parent :pose="currentPose">
<Child v-for="items in item" v-bind:key="item" />
</Parent>
`
};
Whenever a posed component changes pose
, that change is communicated throughout all of its children components. Even if they’re not direct children, they still update accordingly.
This makes it super-simple to, for instance, make page-wide route transitions.
Setup
To demonstrate animating children, we’re going to create this sidebar animation:
Follow along by forking this CodeSandbox.
Sidebar (parent)
In our sandbox, look in the script
section. We’re exporting a component that simply toggles an isVisible
boolean every two seconds.
Our template is currently empty, so let’s add a Sidebar
that open and closes depending on the status of isVisible
.
Add a new property to our exported component called components
. In it, add a Sidebar
posed component with a couple of poses, 'visible'
and 'hidden'
:
components: {
Sidebar: posed.ul({
visible: { x: 0 },
hidden: { x: '-100%' }
})
}
In our template
section, lets render this Sidebar
component, passing it either a 'visible'
or 'hidden'
pose depending on isVisible
:
<template>
<Sidebar class="sidebar" :pose="isVisible ? 'visible' : 'hidden'" />
</template>
Already, we can see our sidebar peeking in and out of our page. Let’s add some items to it.
Items (children)
We need a new posed component, this time called Item
. Add it to components
:
Item: posed.li({
visible: { opacity: 1, y: 0 },
hidden: { opacity: 0, y: 20 }
})
We can render this by iterating over the items
array being created our exported component’s data
function. Pass this as a child of Sidebar
:
<template>
<Sidebar class="sidebar" :pose="isVisible ? 'visible': 'hidden'">
<Item class="item" v-for="item in items" v-bind:key="item" />
</Sidebar>
</template>
We’ve only passed pose
to Sidebar
, but all our Item
s are animating in and out, too!
In this example, Item
is a direct child of Sidebar
, but this will still work if it was a far descendant of Sidebar
. You could even add children to Item
and those would be animated correctly, too.
Scheduling animations
Currently, our children animations are being fired at the exact same time as the parent. But, often we’d prefer the child animations to be delayed or staggered.
Luckily, we’ve got properties for that!
delay
The delay
property can be used to delay the animation on the current poser, without affecting the execution of child animations.
So by setting delay: 300
on the sidebar’s closed
pose, the children will all animate out before the sidebar itself.
Sidebar: posed.ul({
open: { x: '0%' },
closed: { x: '-100%', delay: 300 }
});
delayChildren
Conversely, the delayChildren
property can be used to delay all the children animations.
By setting delayChildren
on the sidebar’s open
pose, we can animate the sidebar out and then animate the children in:
Sidebar: posed.ul({
open: { x: '0%', delayChildren: 200 },
closed: { x: '-100%', delay: 300 }
});
staggerChildren
Rather than animating all the children in at once, it’s possible to stagger them in individually. The staggerChildren
prop can be used to determine the delay between each one, starting from after the delayChildren
duration:
Sidebar: posed.ul({
open: {
x: '0%',
delayChildren: 200,
staggerChildren: 50
},
closed: { x: '-100%', delay: 300 },
initialPose: 'closed'
});
staggerDirection
staggerDirection
can be used to determine which order we stagger over the children in. It can either be 1
(first to last, default), or -1
(last to first).
beforeChildren/afterChildren
Setting either beforeChildren
or afterChildren
props to true
will make the parent animation play before or after any children animations.