Cómo construir un administrador de música con Nuxt.js y Express.js

Publicado: 2022-03-10
Resumen rápido ↬ Este artículo presenta cómo Multer agiliza el proceso de manejo de cargas de archivos. También presenta cómo usar Mongoose para interactuar con nuestra base de datos mediante la creación de una aplicación de administrador de música usando Express.js junto con Multer para la carga de música y Nuxt.js (marco Vue) para nuestra interfaz.

El manejo de activos de medios digitales como audio y video en su aplicación puede ser complicado debido a las consideraciones que deben hacerse en el lado del servidor (por ejemplo, redes, almacenamiento y la naturaleza asincrónica del manejo de cargas de archivos). Sin embargo, podemos usar bibliotecas como Multer y Express.js para simplificar nuestro flujo de trabajo en el backend mientras usamos Nuxt.js (marco Vue) para desarrollar las interacciones del front-end.

Cada vez que un cliente web carga un archivo en un servidor, generalmente se envía a través de un formulario y se codifica como multipart/form-data . Multer es un middleware para Express.js y Node.js que facilita el manejo de los llamados multipart/form-data cada vez que los usuarios cargan archivos. En este tutorial, explicaré cómo puede crear una aplicación de administrador de música usando Express.js con Multer para cargar música y Nuxt.js (marco Vue) para nuestra interfaz.

requisitos previos

  • Familiaridad con HTML, CSS y JavaScript (ES6+);
  • Node.js, npm y MongoDB instalados en su máquina de desarrollo;
  • código VS o cualquier editor de código de su elección;
  • Conocimientos básicos de Express.js.
¡Más después del salto! Continúe leyendo a continuación ↓

Creación del servicio back-end

Comencemos por crear un directorio para nuestro proyecto navegando en el directorio y emitiendo npm init -y en su terminal para crear un archivo package.json que administre todas las dependencias de nuestra aplicación.

 mkdir serverside && cd serverside npm init -y

A continuación, instale multer , express y las demás dependencias necesarias para Bootstrap una aplicación Express.js.

 npm install express multer nodemon mongoose cors morgan body-parser --save

A continuación, cree un archivo index.js :

 touch index.js

Luego, en el archivo index.js , inicializaremos todos los módulos, crearemos una aplicación Express.js y crearemos un servidor para conectarse a los navegadores:

 const express = require("express"); const PORT = process.env.PORT || 4000; const morgan = require("morgan"); const cors = require("cors"); const bodyParser = require("body-parser"); const mongoose = require("mongoose"); const config = require("./config/db"); const app = express(); //configure database and mongoose mongoose.set("useCreateIndex", true); mongoose .connect(config.database, { useNewUrlParser: true }) .then(() => { console.log("Database is connected"); }) .catch(err => { console.log({ database_error: err }); }); // db configuaration ends here //registering cors app.use(cors()); //configure body parser app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); //configure body-parser ends here app.use(morgan("dev")); // configire morgan // define first route app.get("/", (req, res) => { res.json("Hola MEVN devs...Assemble"); }); app.listen(PORT, () => { console.log(`App is running on ${PORT}`); });

En primer lugar, incorporamos Express.js al proyecto y luego definimos un puerto en el que se ejecutará nuestra aplicación. A continuación, incorporamos las dependencias body-parser , morgan , mongoose y cors .

Luego guardamos la instancia express en una variable llamada app . Podemos usar la instancia de la app para configurar el middleware en nuestra aplicación tal como configuramos el cors middleware. También usamos la instancia de la app para configurar la ruta raíz que se ejecutará en el puerto que definimos.

Ahora vamos a crear una carpeta /config para nuestra configuración de base de datos y config de multer :

 mkdir config and cd config touch multer.js && touch db.js

Luego abra config/db.js y agregue el siguiente código para configurar nuestra base de datos:

 module.exports = { database: "mongodb://localhost:27017/", secret: "password" };

(Este es en realidad un objeto que contiene la URL de la base de datos y el secreto de la base de datos).

Ejecutar nodemon y navegar a localhost:4000 en su navegador debería mostrarle este mensaje:

 "Hola MEVN devs...Assemble"

Además, así es como debería verse ahora su terminal:

Ejecutando Nodemon usando Terminal
Vista previa del terminal (vista previa grande)

Configuración de modelos, rutas y controladores

Configuremos una estructura de archivos escribiendo lo siguiente:

 mkdir api && cd api mkdir model && cd model && touch Music.js cd .. mkdir controller && cd controller && touch musicController.js cd .. mkdir routes && cd routes && touch music.js

En nuestra terminal, usamos mkdir para crear un nuevo directorio y luego cd para movernos a un directorio. Entonces, comenzamos creando un directorio llamado api y luego pasamos al directorio api .

El comando touch se usa para crear un nuevo archivo dentro de un directorio usando la terminal, mientras que el comando cd se usa para salir de un directorio.

Ahora vayamos a nuestro archivo api/model/Music.js para crear un esquema de música. Un modelo es una clase con la que construimos documentos. En este caso, cada documento será una pieza musical con las propiedades y comportamientos declarados en nuestro esquema:

 let mongoose = require("mongoose"); let musicSchema = mongoose.Schema({ title: { type: String, required: true }, music: { type: Object, required: true }, artist: { type: String, required: true }, created: { type: Date, default: Date.now() } }); let Music = mongoose.model("Music", musicSchema); module.exports = Music;

Vayamos a config/multer para configurar Multer:

 let multer = require("multer"); const path = require("path"); const storage = multer.diskStorage({ destination: (req, res, cb) => { cb(null, "./uploads"); }, filename: (req, file, cb) => { cb(null, new Date().toISOString() + file.originalname); } }); const fileFilter = (req, file, cb) => { if ( file.mimetype === "audio/mpeg" || file.mimetype === "audio/wave" || file.mimetype === "audio/wav" || file.mimetype === "audio/mp3" ) { cb(null, true); } else { cb(null, false); } }; exports.upload = multer({ storage: storage, limits: { fileSize: 1024 * 1024 * 5 }, fileFilter: fileFilter });

En el archivo multer.js , comenzamos configurando una carpeta donde se cargarán todos los archivos de música cargados. Necesitamos hacer que este archivo sea estático definiéndolo en el archivo index.js :

 app.use('/uploads', express.static('uploads'));

Después de eso, escribimos un validador simple que verificará el tipo de archivo MIME antes de cargarlo. Luego definimos la instancia de multer agregando la ubicación de almacenamiento, los límites de cada archivo y el validador que creamos.

Crea las rutas necesarias

Ahora vamos a crear nuestras rutas. A continuación se muestra la lista de puntos finales que crearemos.

HTTP POST /music Agregar música nueva
HTTP GET /music Obtener toda la música
HTTP DELETE /music/:blogId eliminar una musica

Comencemos por crear la ruta del blog. Dirígete a api/routes/music.js y escribe el siguiente código:

 const express = require("express"); const router = express.Router(); const musicController = require("../controller/musicController"); const upload = require("../../config/multer"); router.get("/", musicController.getAllMusics); router.post("/", upload.upload.single("music"), musicController.addNewMusic); router.delete("/:musicId", musicController.deleteMusic); module.exports = router;

Nota : Ahora cada vez que hagamos una solicitud de get a /music . la ruta llama a la función getAllMusic que se encuentra en el archivo 'controladores'.

Vayamos a api/controllers/musicController para definir los controladores. Comenzamos escribiendo una función para obtener toda la música en nuestra base de datos utilizando el método mongoose db.collection.find que devolverá todos los elementos de esa colección.

Después de hacer eso, escribimos otra función que creará una pieza de música nueva en la base de datos. Necesitamos crear una nueva instancia de música usando la new palabra clave y luego definir el objeto de música. Después de hacer esto, usaremos el método de save de mongoose para agregar música nueva a la base de datos.

Para eliminar una pieza musical, necesitamos usar el método de remove de mongoose simplemente pasando la identificación de la música como un parámetro en la instancia de remove . Esto da como resultado que Mongoose busque en la colección de música que tiene esa identificación en particular y luego la elimine de esa colección.

 let mongoose = require("mongoose"); const Music = require("../model/Music"); exports.getAllMusics = async (req, res) => { try { let music = await Music.find(); res.status(200).json(music); } catch (err) { res.status(500).json(err); } }; exports.addNewMusic = async (req, res) => { try { const music = new Music({ title:req.body.title, artist:req.body.artist, music:req.file }); let newMusic = await music.save(); res.status(200).json({ data: newMusic }); } catch (err) { res.status(500).json({ error: err }); } }; exports.deleteMusic = async (req, res) => { try { const id = req.params.musicId; let result = await Music.remove({ _id: id }); res.status(200).json(result); } catch (err) { res.status(500).json(err); } };

Por último, pero no menos importante, para probar las rutas, debemos registrar las rutas musicales en nuestro archivo index.js :

 const userRoutes = require("./api/user/route/user"); //bring in our user routes app.use("/user", userRoutes);

Prueba de los puntos finales

Para probar nuestros puntos finales, usaremos POSTMAN.

Agregar música nueva

Para probar la funcionalidad Add Music , configure el método de la solicitud haciendo clic en el menú desplegable de métodos. Después de hacer esto, escriba la URL del punto final y luego haga clic en la pestaña del cuerpo para seleccionar cómo desea enviar sus datos. (En nuestro caso, usaremos el método de datos de formulario).

Así que haga clic en los datos del formulario y configure la clave de su modelo. Mientras lo configura, asigne a las teclas algún valor como se muestra en la imagen a continuación:

Prueba Agregar nueva API de música usando Postman
Prueba Agregar nueva API de música en el panel de Postman (vista previa grande)

Después de hacer esto, haga clic en 'Enviar' para realizar la solicitud.

Listado de toda la música

Para enumerar toda la música en nuestra base de datos, debemos escribir la URL del punto final en la sección de URL provista. Después de hacer esto, haga clic en el botón 'Enviar' para realizar la solicitud.

Probando la API de listado usando Postman
Prueba de la API de listado en el panel de control de Postman (vista previa grande)

Eliminación de música

Para eliminar una pieza musical, debemos pasar la music id como parámetro.

Probar la API de eliminación con Postman
Prueba del panel de control del cartero de la API de eliminación (vista previa grande)

¡Eso es todo!

Construyendo la interfaz

Para nuestra interfaz, usaremos un marco Vue: Nuxt.js.

“Nuxt es un marco progresivo basado en Vue.js para crear aplicaciones web modernas. Se basa en las bibliotecas oficiales de Vue.js (vue, vue-router y vuex) y potentes herramientas de desarrollo (webpack, Babel y PostCSS)”.

— Guía de NuxtJS

Para crear una nueva aplicación Nuxt.js, abre tu terminal y escribe lo siguiente (con musicapp como el nombre de la aplicación que construiremos):

 $ npx create-nuxt-app musicapp

Durante el proceso de instalación, se nos harán algunas preguntas sobre la configuración del proyecto:

Project name aplicación de música
project description Una aplicación de administrador de música simple
Author name <tu nombre>
Package manager npm
UI framework Vista previa de Bootstrap
custom ui framework ninguna
Nuxt modules Axios, pwa (use la barra espaciadora de su teclado para seleccionar elementos)
Linting tool más bonita
test framework Ninguna
Rendering Mode universales (RSS)
development tool Jsonconfig.json

Después de seleccionar todo esto, tenemos que esperar un poco a que se configure el proyecto. Una vez que esté listo, muévase a la carpeta /project y sirva el proyecto de la siguiente manera:

 cd musicapp && npm run dev

Abra el proyecto en cualquier editor de código de su elección y luego abra el proyecto en el navegador accediendo a localhost:3000 .

Vista previa del proyecto Nuxt.js
Vista previa del proyecto Nuxt.js (vista previa grande)

Configuración de Axios

Usaremos axios para realizar una solicitud HTTP a nuestro servidor back-end. Axios ya está instalado en nuestro proyecto, por lo que solo tenemos que configurar la baseURL en nuestro servidor backend.

Para hacer esto, abra el archivo nuxt.config.js en el directorio root y agregue la baseURL en el objeto axios .

 axios: { baseURL:'https://localhost:4000' },

Creación del administrador de música

Configuración de la interfaz de usuario

Comencemos por limpiar la interfaz de usuario. Abra el archivo pages/index.vue y elimine todo el código que contiene con lo siguiente:

 <template> <div>Hello</div> </template>

Después de hacer esto, solo debería poder ver un "Hola" en el navegador.

En el directorio root , cree una carpeta /partials . Dentro de la carpeta /partials partials, cree un archivo navbar.vue y agregue el siguiente código:

 <template> <header> <nav class="navbar navbar-expand-lg navbar-light bg-info"> <div class="container"> <a class="navbar-brand" href="#">Music App</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation" > <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse justify-content-end"> <ul class="navbar-nav"> <li class="nav-item active"> <a class="nav-link" href="#">Player</a> </li> <li class="nav-item"> <a class="nav-link" href="#">Manager</a> </li> </ul> </div> </div> </nav> </header> </template> <style scoped> .nav-link, .navbar-brand { color: #ffff !important; } </style>

Nota : Usaremos el componente para navegar por las páginas de nuestra aplicación. Este será solo un componente simple compuesto por la barra de navegación Bootstrap navbar Consulte la documentación oficial de Bootstrap para obtener más referencias.

A continuación, definamos un diseño personalizado para la aplicación. Abra la carpeta /layouts , reemplace el código en el archivo default.vue con el código a continuación.

 <template> <div> <navbar /> <nuxt /> </div> </template> <script> import navbar from '@/partial/navbar' export default { components: { navbar } } </script>

Importamos la navbar de navegación a este diseño, lo que significa que todas las páginas de nuestra aplicación tendrán ese componente de navbar de navegación. (Este será el componente en el que se montarán todos los demás componentes de nuestra aplicación).

Después de esto, debería poder ver esto en su navegador:

Componente Nuxt.js Navbar después de la modificación
Componente Nuxt.js Navbar (vista previa grande)

Ahora configuremos la interfaz de usuario para nuestro administrador. Para hacer esto, necesitamos crear una carpeta /manager dentro de la carpeta de componentes y luego agregar un archivo a la carpeta llamada manager.vue .

En este archivo, agregue el siguiente código:

 <template> <section class="mt-5"> <div class="container mb-4"> <div class="row"> <div class="col-md-12"> <div class="card"> <div class="card-body"> <div class="card-title mb-4"> <h4>Add Music</h4> </div> <form> <div class="form-group"> <label for="title">Title</label> <input type="text" class="form-control" /> </div> <div class="form-group"> <label for="artist">Artist</label> <input type="text" class="form-control" /> </div> <div class="form-group"> <label for="artist">Music</label> <div class="custom-file"> <input type="file" class="custom-file-input" /> <label class="custom-file-label" for="customFile">Choose file</label> </div> </div> <div class="form-group"> <button class="btn btn-primary">Submit</button> </div> </form> </div> </div> </div> </div> </div> <div class="container"> <div class="row"> <div class="col-md-12"> <div class="card bg-light p-1 showdow-sm"> <div class="card-title"> <button class="btn btn-info m-3">Add Music</button> </div> <div class="card-body"> <table class="table"> <thead> <tr> <th scope="col">#</th> <th scope="col">Title</th> <th scope="col">Artist</th> <th scope="col">Date created</th> <th scope="col">Action</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>Demo Title</td> <td>Wisdom.vue</td> <td>12/23/13</td> <td> <button class="btn btn-info">Delete</button> </td> </tr> </tbody> </table> </div> </div> </div> </div> </div> </section> </template>

Nota : esta es solo una plantilla simple de Bootstrap para agregar música a nuestra aplicación. El formulario definirá una plantilla de tabla que enumerará toda la música que se puede encontrar en nuestra base de datos.

Después de definir este componente, debemos registrarlo en la carpeta /pages para iniciar el enrutamiento.

Nuxt.js no tiene un archivo 'router.js' como Vue.js. Utiliza la carpeta de páginas para el enrutamiento. Para obtener más detalles, visite el sitio web de Nuxt.js.

Para registrar el componente, cree una carpeta /manager dentro de la carpeta /pages y cree un archivo index.vue . Luego, coloque el siguiente código dentro del archivo:

 <template> <div> <manager /> </div> </template> <script> import manager from '@/components/manager/manager' export default { components: { manager } } </script>

Este es el componente que aparecerá en la ruta de nuestras pages .

Después de hacer esto, dirígete a tu navegador y navega a /manager ; deberías ver esto:

Interfaz de usuario del administrador de música
Interfaz de usuario del administrador de música (vista previa grande)

Listado de toda la música

Continuemos creando una función que recuperará toda la música. Esta función se registrará en el gancho del ciclo de vida creado, de modo que cada vez que se cree el componente, se llamará a la función.

Comencemos creando una variable en la instancia de vue que contendrá toda la música:

 allmusic = []; musicLoading: false,

Luego, defina una función getAllMusics y agregue el siguiente código:

 async getAllMusics() { this.musicLoading = true try { let data = await this.$axios.$get('/music') this.allmusic = data this.musicLoading = false } catch (err) { this.musicLoading = false swal('Error', 'Error Fetting Musics', 'error') } }

A continuación, regístrese dentro del enlace del ciclo de vida creado:

 created() { this.getAllMusics() }

Salida de los datos

Ahora es el momento de generar todas las canciones en la mesa que hemos creado anteriormente:

 <table class="table"> <thead> <tr> <th scope="col">#</th> <th scope="col">Title</th> <th scope="col">Artist</th> <th scope="col">Date created</th> <th scope="col">Action</th> </tr> </thead> <div v-if="musicLoading" class="spinner-border" role="status" > <span class="sr-only">Loading...</span> </div> <tbody v-else> <tr v-for="(music, index) in allmusic" :key="index"> <td>{{ index + 1 }}</td> <td>{{ music.title }}</td> <td>{{ music.artist }}</td> <td>{{ music.created }}</td> <td> <button class="btn btn-info" @click="deleteMusic(music._id)">Delete</button> </td> </tr> </tbody> </table>

¿Recuerdas la tabla que creamos antes? Bueno, tendremos que recorrer la respuesta que recibimos de nuestro backend para enumerar toda la música recibida de la base de datos.

Agregar música

Para agregar una nueva pieza musical, debemos realizar una solicitud HTTP al servidor back-end con los detalles de la música. Para hacer esto, comencemos modificando la forma y el manejo de las cargas de archivos.

En el formulario, debemos agregar un detector de event que escuchará el formulario cuando se envíe. En el campo de input , agregamos un modelo v- para vincular el valor al campo de entrada.

 <form @submit.prevent="addNewMusic"> <div class="form-group"> <label for="title">Title</label> <input type="text" v-model="musicDetails.title" class="form-control" /> </div> <div class="form-group"> <label for="artist">Artist</label> <input type="text" v-model="musicDetails.artist" class="form-control" /> </div> <div class="form-group"> <label for="artist">Music</label> <div class="custom-file"> <input type="file" ref="file" v-on:change="handleFileUpload()" class="custom-file-input" /> <label class="custom-file-label" for="customFile">Choose file</label> </div> </div> <div class="form-group"> <button class="btn btn-primary" :disabled="isDisabled"> <span class="spinner-border spinner-border-sm" v-if="addLoading" role="status" aria-hidden="true" ></span>Submit </button> </div> </form>

Y la sección del script debería verse así:

 <script> export default { data() { return { musicDetails: { title: '', artist: '', music: '' }, allmusic = [], musicLoading: false, isValid: false; addLoading: false, } }, computed: { isDisabled: function() { if ( this.musicDetails.title === '' || this.musicDetails.artist === '' || this.musicDetails.music === '' ) { return !this.isValid } } }, methods: { handleFileUpload() { this.musicDetails.music = this.$refs.file.files[0] console.log(this.musicDetails.music.type) }, addNewMusic() { let types = /(\.|\/)(mp3|mp4)$/i if ( types.test(this.musicDetails.music.type) || types.test(this.musicDetails.music.name) ) { console.log('erjkb') } else { alert('Invalid file type') return !this.isValid } } } } </script>

Definiremos una función que enviará una solicitud a nuestro servicio de back-end para crear cualquier música nueva que se haya agregado a la lista. También. necesitamos escribir una función de validación simple que verificará el tipo de archivo para que los usuarios solo puedan cargar archivos con una extensión de .mp3 y .mp4 .

Es importante definir una propiedad calculada para asegurarse de que nuestro campo de entrada no esté vacío. También necesitamos agregar un validador simple que se asegure de que el archivo que estamos tratando de cargar sea en realidad un archivo de música.

Continuemos editando la función addMusic para realizar una solicitud a nuestro servicio de back-end. Pero antes de hacer esto, primero sweetalert , que nos proporcionará una buena ventana modal. Para hacer esto, abre tu terminal y escribe lo siguiente:

 npm i sweetalert

Después de instalar el paquete, cree un archivo sweetalert.js en la carpeta /plugins y agregue esto:

 import Vue from 'vue'; import swal from 'sweetalert'; Vue.prototype.$swal = swal;

Luego, registre el complemento en el archivo nuxt.config.js dentro de la instancia del complemento de esta manera:

 plugins: [ { src: '~/plugins/sweetalert' } ],

Ahora hemos configurado con éxito sweetalert en nuestra aplicación, por lo que podemos continuar y editar la función addmusic a esto:

 addNewMusic() { let types = /(\.|\/)(mp3|mp4)$/i if ( types.test(this.musicDetails.music.type) || types.test(this.musicDetails.music.name) ) { let formData = new FormData() formData.append('title', this.musicDetails.title) formData.append('artist', this.musicDetails.artist) formData.append('music', this.musicDetails.music) this.addLoading = true this.$axios .$post('/music', formData) .then(response => { console.log(response) this.addLoading = false this.musicDetails = {} this.getAllMusics() // we will create this function later swal('Success', 'New Music Added', 'success') }) .catch(err => { this.addLoading = false swal('Error', 'Something Went wrong', 'error') console.log(err) }) } else { swal('Error', 'Invalid file type', 'error') return !this.isValid } },

Escribamos un script simple que alternará el formulario, es decir, solo debería mostrarse cuando queramos agregar música nueva.

Podemos hacer esto editando el botón 'Agregar música' en la tabla que muestra toda la música que se puede encontrar:

 <button class="btn btn-info m-3" @click="initForm"> {{addState?"Cancel":"Add New Music"}} </button>

Luego, agregue un estado que contendrá el estado del formulario en la propiedad de data :

 addState: false

Después de hacer esto, definamos la función initForm :

 initForm() { this.addState = !this.addState },

Y luego agregue v-if="addState" al div que contiene el formulario:

 <div class="card" v-if="addState">

Eliminación de música

Para eliminar música, debemos llamar al punto final de delete y pasar la music id como un parámetro. Agreguemos un evento de click al botón 'Eliminar' que activará la función para eliminar una función:

 <button class="btn btn-info" @click="deleteMusic(music._id)">Delete</button>

La función de delete realizará una solicitud HTTP a nuestro servicio de back-end. Después de obtener el ID de la música del parámetro de la función deleteMusic , agregaremos el ID en la URL que estamos usando para enviar la solicitud. Esto especifica la pieza musical exacta que debe eliminarse de la base de datos.

 deleteMusic(id) { swal({ title: 'Are you sure?', text: 'Once deleted, you will not be able to recover this Music!', icon: 'warning', buttons: true, dangerMode: true }).then(willDelete => { if (willDelete) { this.$axios .$delete('/music/' + id) .then(response => { this.getAllMusics() swal('Poof! Your Music file has been deleted!', { icon: 'success' }) }) .catch(err => { swal('Error', 'Somethimg went wrong', 'error') }) } else { swal('Your Music file is safe!') } }) }

Con todo esto, acabamos de construir nuestro administrador de música. Ahora es el momento de construir el reproductor de música.

Comencemos por crear una nueva carpeta en la carpeta de componentes llamada /player . Luego, cree un archivo player.vue dentro de esta carpeta y agregue esto:

 <template> <section> <div class="container"> <div class="row"> <div class="col-md-12"> <h3 class="text-center">Player</h3> </div> </div> </div> </section> </template> <script> export default { data() { return {} } } </script> <style scoped> </style>

A continuación, importemos este componente al archivo index.vue en la carpeta /pages . Reemplace el código en el archivo index.vue por este:

 <template> <div> <player /> </div> </template> <script> import player from '@/components/player/player' export default { components: { player } } </script>

Configuremos el enrutamiento en nuestro componente de navbar de navegación para habilitar el enrutamiento entre nuestras páginas.

Para enrutar en una aplicación Nuxt.js, se nuxt-link después de lo cual ha especificado la página para esa ruta a una instancia en particular. Así que editemos el código en el componente partials/navbar de navegación a esto:

 <template> <header> <nav class="navbar navbar-expand-lg navbar-light bg-info"> <div class="container"> <nuxt-link to="/" class="navbar-brand">Music App</nuxt-link> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation" > <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse justify-content-end"> <ul class="navbar-nav"> <li class="nav-item active"> <nuxt-link to="/" class="nav-link">Player</nuxt-link> </li> <li class="nav-item"> <nuxt-link to="/manager" class="nav-link">Manager</nuxt-link> </li> </ul> </div> </div> </nav> </header> </template> <style scoped> .nav-link, .navbar-brand { color: #ffff !important; } </style>

Con esto, podemos navegar por nuestras páginas usando la barra de navegación.

Construyendo el jugador

Antes de comenzar, debemos extender Webpack para cargar archivos de audio. Los archivos de audio deben ser procesados ​​por file-loader . Este cargador ya está incluido en la configuración predeterminada de Webpack, pero no está configurado para manejar archivos de audio.

Para hacer esto, vaya al archivo nuxt.config.js y modifique el objeto de build a esto:

 build: { extend(config, ctx) { config.module.rules.push({ test: /\.(ogg|mp3|mp4|wav|mpe?g)$/i, loader: 'file-loader', options: { name: '\[path\][name].[ext]' } }) } }

A continuación, escribamos una función que obtenga todas las canciones y luego usemos el constructor de Audio para reproducir la primera canción en la matriz allMusic .

Para empezar, modifiquemos nuestro archivo player.vue a esto:

 <template> <section v-if="allMusic"> <div class="container"> <div class="row"> <div class="col-md-12"> <h3 class="text-center">Player</h3> </div> </div> <div class="row"> <div class="col-md-6"> <span>{{this.current.title}} - {{this.current.artist}}</span> </div> </div> </div> </section> </template> <script> export default { data() { return { current: { title: '', artist: '' }, song: true, isplaying: false, allMusic: null, index: 0, player: '' } }, methods: { async initPlayer() { if (this.allMusic !== []) { this.current = await this.allMusic[this.index] this.player.src = `https://localhost:4000/${this.current.music.path}` } else { this.song = true } }, async getAllSongs() { try { let response = await this.$axios.$get('/music') console.log(response) if (response === []) { this.song = true this.current = null } else { this.song = false this.allMusic = response } await this.initPlayer() } catch (err) { this.current = null console.log(err) } } }, created() { if (process.client) { this.player = new Audio() } this.getAllSongs() } } </script> <style scoped> </style>

Una vez que se sirve el archivo, la música se reproducirá de fondo y luego debería poder ver esto en su navegador:

Interfaz de usuario del reproductor de música
Interfaz de usuario del reproductor de música (vista previa grande)

Para detener la música, todo lo que necesita hacer es comentar await player.play() en la función initPlayer .

Creación de la interfaz de usuario del reproductor

Ahora definamos la interfaz de usuario de nuestro reproductor de música reemplazando la plantilla en nuestro archivo player.vue con lo siguiente:

 <template> <section v-if="allMusic"> <div class="container"> <div class="row mb-5"> <div class="col-md-12"> <h3 class="text-center">Player</h3> </div> </div> <div class="row mt-5"> <div class="col-md-6"> <img src="https://images.pexels.com/photos/3624281/pexels-photo-3624281.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" class="image" /> <div class="card player_card"> <div class="card-body"> <h6 class="card-title"> <b>{{this.current.title}} - {{this.current.artist}}</b> </h6> <div> <i class="fas fa-backward control mr-4"></i> <i class="fas fa-play play"></i> <i class="fas fa-pause play"></i> <i class="fas fa-forward control ml-4"></i> </div> </div> </div> </div> <div class="col-md-6"> <div class="card shadow"> <table class="table"> <thead> <tr> <th scope="col">#</th> <th scope="col">Title</th> <th scope="col">Artist</th> <th scope="col">Action</th> </tr> </thead> <tbody> <tr> <th scope="row">1</th> <td>Mark</td> <td>Otto</td> <td> <button class="btn btn-primary">Play</button> </td> </tr> </tbody> </table> </div> </div> </div> </div> </section> </template>

Luego, agregue el siguiente estilo en la sección de style :

 <style scoped> .image { border-radius: 5px !important; position: relative; height: 300px; width: 100%; } .player_card { text-align: center; bottom: 20px; margin: 0px 40px; } .text-muted { font-size: 15px; } .play { font-size: 40px; } .control { font-size: 25px; } </style>

Después de modificar esto, el reproductor debería verse así:

Interfaz de usuario final del reproductor de música
Interfaz de usuario final del reproductor de música (vista previa grande)

Agregar la función de reproducción

Continuaremos mostrando la descripción de la música en la tabla. Para hacer esto, reemplace la tabla con el siguiente código:

 <table class="table"> <thead> <tr> <th scope="col">#</th> <th scope="col">Title</th> <th scope="col">Artist</th> <th scope="col">Action</th> </tr> </thead> <tbody> <tr v-for="(music,index) in allMusic" :key="index"> <th scope="row">{{index+1}}</th> <td>{{music.title}}</td> <td>{{music.artist}}</td> <td> <button class="btn btn-primary">Play</button> </td> </tr> </tbody> </table>

No queremos mostrar los íconos de 'Reproducir' y 'Pausa' al mismo tiempo. En su lugar, queremos una situación en la que cuando se reproduzca la canción, se muestre el icono de 'Pausa'. Además, cuando la canción está en pausa, se debe mostrar el icono de reproducción.

Para lograr esto, debemos establecer un estado de isPlaying en la instancia false y luego usar esta instancia para alternar los íconos. Después de eso, agregaremos una función a nuestro icono 'Reproducir'.

 isplaying:false

Después de hacer esto, modifique su icono 'Reproducir' y 'Pausa' a esto:

 <i class="fas fa-play play" v-if="!isplaying" @click="play"></i> <i class="fas fa-pause play" v-else></i>

Con todo esto vamos a definir el método de play :

 play(song) { console.log(song) if (song) { this.current = song this.player.src = `https://localhost:4000/${this.current.music.path}` } this.player.play() this.isplaying = true },

En primer lugar, obtenemos la canción actual y la pasamos al parámetro de function . Luego definimos la instancia de JavaScript Audio() . A continuación, verificamos si la canción es nula: si no lo es, configuramos this.current a la canción que pasamos en el parámetro, y luego llamamos a la instancia del reproductor de Audio . (Además, no olvide que tenemos que establecer el estado isPlaying en true cuando se reproduce la música).

Agregar la función de pausa

Para pausar una canción, usaremos el método de pausa de Audio . Necesitamos agregar un evento de click al ícono de pausa:

 <i class="fas fa-pause play" @click="pause" v-else></i>

Y luego defina la función en la instancia de methods :

pause() { this.player.pause() this.isplaying = false },

Reproducir una canción de la lista de música

Esto es bastante simple de implementar. Todo lo que tenemos que hacer es agregar un evento de click que cambiará el parámetro de la song en el método de play a la canción que acabamos de crear.

Simplemente modifique el botón de play en la tabla de la lista de música a esto:

 <button class="btn btn-primary" @click="play(music)">Play</button>

¡Y ahí lo tienes!

Agregar la siguiente función

Para agregar la siguiente función, necesitamos incrementar el índice en uno. Para hacer esto, agregue un evento de click al siguiente icono:

 @click="next"

Y luego defina la función prev en la instancia de methods :

 next() { this.index++ if (this.index > this.allMusic.length - 1) { this.index = 0 } this.current = this.allMusic[this.index] this.play(this.current) },

Este condicional es responsable de reproducir todas las canciones siempre que se haya reproducido la última canción de la lista.

Agregar la función previous

En realidad, esto es lo opuesto a la siguiente función, así que agreguemos un evento de click a la función anterior:

 @click="prev"

A continuación, definimos la función anterior:

 prev() { this.index-- if (this.index < 0) { this.index = this.allMusic.length - 1 } this.current = this.allMusic[this.index] this.play(this.current) },

¡Nuestra aplicación de reproductor de música ya está completa!

Conclusión

En este artículo, analizamos cómo podemos crear un administrador de música con Nuxt.js y Express.js. En el camino, vimos cómo Multer agiliza el proceso de manejo de cargas de archivos y cómo usar Mongoose para interactuar sin una base de datos. Finalmente, usamos Nuxt.js para crear la aplicación cliente, lo que le da una sensación rápida y ágil.

A diferencia de otros marcos, crear una aplicación con Nuxt.js y Express.js es bastante fácil y rápido. Lo bueno de Nuxt.js es la forma en que administra sus rutas y le ayuda a estructurar mejor sus aplicaciones.

  • Puede acceder a más información sobre Nuxt.js aquí.
  • Puedes acceder al código fuente en Github aquí