Cómo construir un administrador de música con Nuxt.js y Express.js
Publicado: 2022-03-10El 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.
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:
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:
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.
Eliminación de música
Para eliminar una pieza musical, debemos pasar la music id
como parámetro.
¡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
.
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:
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:
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:
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í:
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í