Blog>
Snippets

List Reordering with Animations

Animate the reordering of a draggable list, providing visual feedback when items change position, using Vue's <TransitionGroup> component.
new Vue({
  el: '#app',
  data: {
    items: [
      { id: 1, name: 'Item 1' },
      { id: 2, name: 'Item 2' },
      // ... add additional list items here
    ]
  },
  methods: {
    onMove({ relatedContext, draggedContext }) {
      const relatedElement = relatedContext.element;
      const draggedElement = draggedContext.element;
      const relatedPosition = relatedContext.component.$el.getBoundingClientRect();
      const draggedPosition = draggedContext.component.$el.getBoundingClientRect();

      // Calculate the translation required for the swap animation
      const translation = draggedPosition.top < relatedPosition.top
        ? relatedPosition.height
        : -relatedPosition.height;

      // Apply the transformation
      requestAnimationFrame(() => {
        relatedContext.component.$el.style.transform = `translateY(${translation}px)`;
        relatedContext.component.$el.style.transition = 'transform 0.5s';

        requestAnimationFrame(() => {
          relatedContext.component.$el.style.transform = '';
        });
      });
    }
  }
})
Sets up a new Vue instance binding to an element with the id 'app'. Contains a data property 'items', which is an array of objects representing the list items. Each objetc has an 'id' and a 'name'. A method 'onMove' animates the transition when items are rearranged. It uses requestAnimationFrame to achieve a smooth transition effect.
<template>
  <div id="app">
    <transition-group name="list" tag="ul" @change="onMove">
      <li v-for="item in items" :key="item.id" class="list-item">
        {{ item.name }}
        <button @click="removeItem(item)">Remove</button>
      </li>
    </transition-group>
  </div>
</template>

<script>
// ... Vue instance goes here (from the previous code piece)
</script>

<style>
  .list-item {
    padding: 10px;
    background: #f9f9f9;
    border: 1px solid #ccc;
    margin-bottom: 5px;
    list-style-type: none;
    cursor: pointer;
  }

  .list-enter-active, .list-leave-active {
    transition: all 0.5s;
  }

  .list-enter, .list-leave-to {
    opacity: 0;
    height: 0;
    padding: 0;
    margin-bottom: 0;
  }
</style>
Provides the Vue template containing a transition-group with the class 'list'. It binds the 'onMove' method to the 'change' event of the transition group. Each list item is draggable and has a 'remove' button associated with it (the 'removeItem' method would need to be implemented). It also includes CSS for styling the list and the animations.