JSFiddle - React, Tailwind, and code Playground
changing transitions on transition-group based on state of list
by Travis Almand
HTML
<p>Pick the cities in order you would wish to visit.</p>
<div id="app">
<div class="container">
<ul class="list-back">
<li v-for="(city, index) in cities" :key="city" @click="chooseCity(index)"></li>
</ul>
<transition-group :name="currentListTransition" tag="ul" class="list">
<li v-for="(item, index) in selectedItems" :key="item">{{ item }}</li>
</transition-group>
</div>
<div class="container">
<ul class="list">
<li class="city" v-for="(city, index) in cities" :key="city" @click="chooseCity(index)">{{ city }}</li>
</ul>
</div>
<div class="panel">
<button class="clear" @click="clearSelection">clear</button>
</div>
</div>
SCSS
#app {
align-items: center;
display: flex;
flex-wrap: wrap;
height: 100vh;
justify-content: center;
width: 100vw;
}
.container {
height: 150px;
margin: 20px;
position: relative;
width: 150px;
}
.list,
.list-back {
align-items: center;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: flex-start;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
li {
align-items: center;
display: flex;
flex-shrink: 0;
height: 24px;
justify-content: center;
margin-bottom: 4px;
width: 100%;
}
}
.list-back li {
background-color: #E0E0E0;
border-radius: 24px;
}
.city {
background-color: #E0E0E0;
border-radius: 24px;
cursor: pointer;
transition: 0.5s;
&:hover {
background-color: #307B21;
color: #F5F5F5;
}
&.selected {
opacity: 0.5;
pointer-events: none;
}
}
.panel {
display: flex;
justify-content: center;
width: 100%;
.clear {
background-color: #C11826;
border: {
radius: 8px;
style: none;
}
color: #F5F5F5;
cursor: pointer;
padding: 8px 16px;
}
}
.top-enter-active, .top-leave-active { transition: 0.5s; }
.top-enter, .top-leave-to { opacity: 0; transform: translate3d(0, -40px, 0); }
.top-move { opacity: 0.5; transition: 0.5s; }
.left-enter-active, .left-leave-active { transition: 0.5s; }
.left-enter, .left-leave-to { opacity: 0; transform: translate3d(-40px, 0, 0); }
.left-move { opacity: 0.5; transition: 0.5s; }
.right-enter-active, .right-leave-active { transition: 0.5s; }
.right-enter, .right-leave-to { opacity: 0; transform: translate3d(40px, 0, 0); }
.right-move { opacity: 0.5; transition: 0.5s; }
.bottom-enter-active, .bottom-leave-active { transition: 0.5s; }
.bottom-enter, .bottom-leave-to { opacity: 0; transform: translate3d(0, 30px, 0); }
.bottom-move { opacity: 0.5; transition: 0.5s; }
Vue
new Vue({
el: "#app",
data: {
selectedItems: [],
cities: ['Chicago', 'New York', 'Seattle', 'Miami', 'Boston'],
currentListTransition: 'top'
},
methods: {
chooseCity: function (index) {
let selectedLength = this.selectedItems.length;
let citiesLength = this.cities.length;
let clt = this.currentListTransition;
if (selectedLength === 0) {
clt = 'top';
} else if (selectedLength > 0 && selectedLength < citiesLength - 1) {
clt = clt === 'top' || clt === 'left' ? 'right' : 'left';
} else if (selectedLength === citiesLength - 1) {
clt = 'bottom';
}
this.currentListTransition = clt;
this.selectedItems.push(this.cities[index]);
document.querySelector(`.city:nth-child(${index + 1})`).classList.add('selected');
},
clearSelection: function () {
this.currentListTransition = 'right';
this.selectedItems = [];
document.querySelectorAll('.city.selected').forEach(element => {
element.classList.remove('selected');
});
}
}
})