Goal
Use GSAP Flip
to animate the div._selected
when clicking another item.
Problem
Clicking on an item selects it properly, but doesn’t animate. The reason is because it thinks that div._selected
has left the DOM. It’s there but in a new position.
As an aside, the animation works correctly when the List.vue
data changes.
Places.vue
<template>
<list>
<list-item
class="place"
v-for="place in places"
:key="place.id"
@click="selectPlace(place)"
:selected="place.id === $store.state.places.selected_record_id">
<div class="name">{{ place.name }}</div>
</list-item>
</list>
</template>
<script>
export default {
name: 'places-page',
methods: {
selectRecord ({ id }) {
this.selected_record = id;
}
}
}
</script>
ListItem.vue
<template>
<li class="_item" @click="$emit('click')">
<slot></slot>
<!-- This is what moves around -->
<div class="_selected"
data-flip-id="selected"
v-if="selected">
</div>
</li>
</template>
<script>
export default {
name: 'list-item',
props: {
selected: { type: Boolean, default: false }
}
}
</script>
List.vue
<template>
<ul class="list-control">
<slot></slot>
</ul>
</template>
<script>
export default {
name: 'list-control',
data () {
return {
state: null
};
},
beforeUpdate () {
this.$data.state = Flip.getState(gsap.utils.toArray('.list-control [data-flip-id]'));
},
updated () {
Flip.from(this.$data.state, {
duration: 0.8,
ease: 'expo.out',
simple: true,
nested: true,
onEnter: elements => {
console.log('*** onEnter', elements);
},
// When clicking on an item, this thinks that `div._selected`
// has left the DOM and didn’t come back. Seems like
// a race condition, but unsure how to proceed since the DOM
// should be fully `updated` at this point
onLeave: elements => {
console.log('*** onLeave', elements);
}
});
}
}
</script>
Need to add targets: gsap.utils.toArray('.list-control [data-flip-id]')
. So:
Flip.from(this.$data.state, {
// ...
targets: gsap.utils.toArray('.list-control [data-flip-id]'),
// ...
});