Paso a paso: implementar interfaces Draggables con VueJS

Foto Alejandro

May 20, 2020 Compartir

vue tutoriales

Implementación de una interfaz animada con elementos draggables (arrastrar y soltar) con VueJS.

Live demo
Código fuente

Prerequisitos

Para este tutorial consideraremos que ya tienes conocimientos básicos de Vue JS y que ya sabes cómo integrar TailwindCSS a Vue JS. En resumen debes estar familiarizado con:

Metas

Construiremos una aplicación sencilla que consistirá en un listado básico de usuarios. Veremos cómo lograr la funcionalidad de "arrastrar y soltar" elementos en el DOM.

Interfaces draggables con Vue

PASOS PRELIMINARES


1. Diseño inicial y color de fondo

Editaremos el archivo App.vue el cual corresponde al componente principal de nuestra aplicación y modificaremos la seccion <template> con lo siguiente:

<template>
    <div id="app" class="min-h-screen w-screen bg-gray-600 flex items-center justify-center">
    </div>
</template>

Con las clases de Tailwind utilizadas estamos estableciendo el color de fondo y centrando todo en la página.

Todas las clases de CSS que vamos a utilizar corresponden al conjunto de clases predeterminado de Tailwind. Puede encontrarlos en la documentación oficial, sin embargo, la mayoría de ellos se explican por sí mismas.

2. Listado de usuarios

Para nuestro ejemplo, el listado de usuarios será declarado e inicializado dentro del objeto data del componente principal App.vue

data() {
    return {
        users: [
            {
                id: 1,
                name: "Evan You",
                avatar: "https://pickaface.net/gallery/avatar/unr_sample_161118_2054_ynlrg.png",
            },
            {
                id: 2,
                name: "Taylor Otwell",
                avatar: "https://pickaface.net/gallery/avatar/freud51c8b3f65e7dc.png"
            },
            {
                id: 3,
                name: "Steve Jobs",
                avatar: "https://pickaface.net/gallery/avatar/Opi51c74d0125fd4.png"
            },
            {
                id: 4,
                name: "Linus Torvalds",
                avatar: "https://pickaface.net/gallery/avatar/unr_yassine_191124_2012_3gngr.png"
            },
            {
                id: 5,
                name: "Bill Gates",
                avatar: "https://pickaface.net/gallery/avatar/elmedinilla541c03412955c.png"
            }
        ]
    }
},

Ahora que ya tenemos la lista de usuarios en nuestra instancia de Vue, podemos mostrarla iterando sobre cada uno de los elementos del array:

<ul>
    <li v-for="user in users" :key="user.id">
        {{ user.name }}
    </li>
</ul>

Y obtenemos...

Interfaces draggables con Vue

Aplicando clases de Tailwind comenzaremos a darle estilos a nuestro listado:

<ul class="w-full max-w-md">
    <li v-for="user in users"
        :key="user.id"
        class="p-4 mb-3 flex justify-between items-center bg-white shadow rounded-lg cursor-move">
        {{ user.name }}
    </li>
</ul>

Nuestro listado quedaría de esta forma:

Interfaces draggables con Vue

Ahora agregaremos algunos detalles más como el avatar y botones de acción.

Como ya tenemos las URL del avatar en nuestro listado de usuarios, los añadiremos a nuestra tarjeta:

<li v-for="user in users"
    :key="user.id"
    class="p-4 mb-3 flex justify-between items-center bg-white shadow rounded-lg cursor-move">
    <div class="flex items-center">
        <img class="w-10 h-10 rounded-full" :src="user.avatar" :alt="user.name">
        <p class="ml-2 text-gray-700 font-semibold font-sans tracking-wide">{{ user.name }}</p>
    </div>
</li>

Interfaces draggables con Vue

Para los botones de acción vamos a usar un conjunto de iconos SVG que se pueden importar como componentes a través de la libreria vue-feather-icons. Para ello debemos instalarla en nuestro proyecto:

npm install vue-feather-icons

Ahora debemos importar los componentes que utilizaremos de la librería que acabamos de instalar:

// En el archivo src/App.vue
<script>
import { Edit3Icon, TrashIcon } from "vue-feather-icons";

export default {
    components: {
        Edit3Icon,
        TrashIcon
    }
}
</script>

Ya podemos hacer uso de los nuevos componentes en el template html. Añadiremos los botones para las acciones editar y eliminar:

<div class="flex">
    <button 
        class="p-1 focus:outline-none focus:shadow-outline text-teal-500 hover:text-teal-600"
        title="Editar usuario">
        <Edit3Icon/>
    </button>
    <button 
        class="p-1 focus:outline-none focus:shadow-outline text-red-500 hover:text-red-600"
        title="Eliminar usuario">
        <TrashIcon/>
    </button>
</div>

Y nuestro listado de usuarios ahora se ve así 🤩

Interfaces draggables con Vue


IMPLEMENTANDO DRAG & DROP


Hemos llegado al punto de este tutorial, implementaremos la funcionalidad de arrastrar y soltar elementos en el DOM:

Interfaces draggables con Vue

Para lograr este efecto utilizaremos la biblioteca Vue Draggable, la cual debemos instalar en nuestra aplicación:

npm install vuedraggable

Luego la importamos en nuestro componente App.vue:

<script>
import { Edit3Icon, TrashIcon } from "vue-feather-icons";
import Draggable from 'vuedraggable'

export default {
    name: 'App',

    components: {
        Edit3Icon,
        TrashIcon,
        Draggable,
    }
}
</script>

Ya estamos listos para hacer que nuestro listado soporte Drag & Drop. Sólo tenemos que "envolverlo" dentro de nuestro nuevo componente. Reemplazaremos las etiquetas <ul> por <Draggable> de la siguiente forma:

<Draggable :list="users">
    <li v-for="user in users"
        :key="user.id">
       <!-- ... -->
    </li>
</Draggable>

Nota que el componente Draggable debe recibir datos para una propiedad llamada list, que en nuestro caso corresponde a nuestro array de usuarios

<Draggable :list="users">

Por otro lado debemos decirle al componente cuál es el elemento al cual se le aplicará el efecto, en nuestro caso es el elemento <ul>, así como los estilos que ya tenía:

<Draggable :list="users" tag="ul" class="w-full max-w-md" ghost-class="moving-card" :animation="200">

La propiedad ghost-class le otorga a nuestro listado una animación suave. Para que funcione debemos añadir los siguientes estilos a nuestro componente App.vue:

<style lang="scss">
    .moving-card {
        @apply opacity-50 bg-gray-100 border border-blue-500;
    }
</style>

¡Hemos terminado!

Aquí está nuestro componente App completo

// Archivo src/App.vue
<template>
    <div id="app" class="min-h-screen w-screen bg-gray-600 flex items-center justify-center">
        <Draggable v-if="users.length > 0" ghost-class="moving-card" tag="ul" class="w-full max-w-md" :list="users" :animation="200">
            <li v-for="user in users"
                :key="user.id"
                class="p-4 mb-3 flex justify-between items-center bg-white shadow rounded-lg cursor-move">
                <div class="flex items-center">
                    <img class="w-10 h-10 rounded-full" :src="user.avatar" :alt="user.name">
                    <p class="ml-2 text-gray-700 font-semibold font-sans tracking-wide">{{ user.name }}</p>
                </div>
                <div class="flex">
                    <button 
                        class="p-1 focus:outline-none focus:shadow-outline text-teal-500 hover:text-teal-600"
                        title="Editar usuario">
                        <Edit3Icon/>
                    </button>
                    <button 
                        class="p-1 focus:outline-none focus:shadow-outline text-red-500 hover:text-red-600"
                        title="Eliminar usuario"
                        v-on:click="deleteUser(user)">
                        <TrashIcon/>
                    </button>
                </div>
            </li>
        </Draggable>
    </div>
</template>

<script>
import { Edit3Icon, TrashIcon } from "vue-feather-icons";
import Draggable from 'vuedraggable'

export default {
    name: 'App',

    components: {
        Draggable,
        Edit3Icon,
        TrashIcon
    },

    data() {
        return {
            users: [
                {
                    id: 1,
                    name: "Evan You",
                    avatar: "https://pickaface.net/gallery/avatar/unr_sample_161118_2054_ynlrg.png",
                },
                {
                    id: 2,
                    name: "Taylor Otwell",
                    avatar: "https://pickaface.net/gallery/avatar/freud51c8b3f65e7dc.png"
                },
                {
                    id: 3,
                    name: "Steve Jobs",
                    avatar: "https://pickaface.net/gallery/avatar/Opi51c74d0125fd4.png"
                },
                {
                    id: 4,
                    name: "Linus Torvalds",
                    avatar: "https://pickaface.net/gallery/avatar/unr_yassine_191124_2012_3gngr.png"
                },
                {
                    id: 5,
                    name: "Bill Gates",
                    avatar: "https://pickaface.net/gallery/avatar/elmedinilla541c03412955c.png"
                }
            ]
        }
    },
}
</script>

<style lang="scss">
    .moving-card {
        @apply opacity-50 bg-gray-100 border border-blue-500;
    }
</style>

Conclusión

En este artículo hemos visto cómo implementar elementos Draggables utilizando Vue JS. Puedes ver el live-demo en este enlace. También puedes descargar aquí el código fuente del proyecto. En el repositorio hay algunas otras mejoras como las funcionalidades de editar, eliminar y agregar un nuevo usuario; también se mejoró un poco la estructura del proyecto creando un componente separado para las tarjetas de usuario. Clónalo y sigue haciéndole mejoras a la aplicación, ¡tu imaginación es el límite! 😉.

Autor

Hola 👋, Soy Alejandro, un desarrollador de software que disfruta crear y mejorar herramientas que resuelvan problemas y hagan que la vida de las personas sea más sencilla, bella y cómoda. Algunas veces escribo sobre las cosas que he aprendido con el tiempo. Espero que el contenido te sea de ayuda.