Como construir um gerenciador de música com Nuxt.js e Express.js
Publicados: 2022-03-10O manuseio de ativos de mídia digital como áudio e vídeo em seu aplicativo pode ser complicado devido às considerações que devem ser feitas no lado do servidor (por exemplo, rede, armazenamento e a natureza assíncrona do manuseio de uploads de arquivos). No entanto, podemos usar bibliotecas como Multer e Express.js para simplificar nosso fluxo de trabalho no back-end enquanto usamos o Nuxt.js (estrutura Vue) para criar as interações de front-end.
Sempre que um cliente da Web faz upload de um arquivo para um servidor, ele geralmente é enviado por meio de um formulário e codificado como multipart/form-data
. Multer
é um middleware para Express.js e Node.js que facilita o manuseio dos chamados multipart/form-data
sempre que seus usuários fazem upload de arquivos. Neste tutorial, explicarei como você pode criar um aplicativo gerenciador de música usando Express.js com Multer para fazer upload de música e Nuxt.js (estrutura Vue) para nosso frontend.
Pré-requisitos
- Familiaridade com HTML, CSS e JavaScript (ES6+);
- Node.js, npm e MongoDB instalados em sua máquina de desenvolvimento;
- Código VS ou qualquer editor de código de sua escolha;
- Conhecimento básico de Express.js.
Construindo o serviço de back-end
Vamos começar criando um diretório para nosso projeto navegando no diretório e emitindo npm init -y
em seu terminal para criar um arquivo package.json que gerencia todas as dependências de nosso aplicativo.
mkdir serverside && cd serverside npm init -y
Em seguida, instale multer
, express
e as outras dependências necessárias para inicializar um aplicativo Express.js.
npm install express multer nodemon mongoose cors morgan body-parser --save
Em seguida, crie um arquivo index.js :
touch index.js
Em seguida, no arquivo index.js , inicializaremos todos os módulos, criaremos um aplicativo Express.js e criaremos um servidor para conexão com 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}`); });
Nós, em primeiro lugar, trazemos o Express.js para o projeto e, em seguida, definimos uma porta na qual nosso aplicativo será executado. Em seguida, trazemos as dependências body-parser
, morgan
, mongoose
e cors
.
Em seguida, salvamos a instância expressa em uma variável chamada app
. Podemos usar a instância do app
para configurar o middleware em nosso aplicativo, assim como configuramos o middleware cors
. Também usamos a instância do app
para configurar a rota raiz que será executada na porta que definimos.
Vamos agora criar uma pasta /config
para nossa configuração de banco de dados e config
de multer
:
mkdir config and cd config touch multer.js && touch db.js
Em seguida, abra config/db.js e adicione o seguinte código para configurar nosso banco de dados:
module.exports = { database: "mongodb://localhost:27017/", secret: "password" };
(Na verdade, este é um objeto que contém a URL do banco de dados e o segredo do banco de dados.)
Executar nodemon
e navegar até localhost:4000
no seu navegador deve fornecer esta mensagem:
"Hola MEVN devs...Assemble"
Além disso, é assim que seu terminal deve se parecer agora:
Configurando modelo, rotas e controladores
Vamos configurar uma estrutura de arquivos digitando o seguinte:
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
Em nosso terminal, usamos mkdir
para criar um novo diretório e, em seguida, cd
para mover para um diretório. Então começamos criando um diretório chamado api
e depois passamos para o diretório api
.
O comando touch
é usado para criar um novo arquivo dentro de um diretório usando o terminal, enquanto o comando cd
é usado para sair de um diretório.
Agora vamos para o nosso arquivo api/model/Music.js para criar um esquema de música. Um modelo é uma classe com a qual construímos documentos. Nesse caso, cada documento será uma música com propriedades e comportamentos conforme declarado em nosso 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;
Vamos para config/multer
para configurar o 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 });
No arquivo multer.js , começamos configurando uma pasta onde serão enviados todos os arquivos de música enviados. Precisamos tornar este arquivo estático definindo-o no arquivo index.js :
app.use('/uploads', express.static('uploads'));
Depois disso, escrevemos um validador simples que verificará o tipo MIME do arquivo antes de fazer o upload. Em seguida, definimos a instância do multer
adicionando o local de armazenamento, os limites de cada arquivo e o validador que criamos.
Crie as Rotas Necessárias
Agora vamos criar nossas rotas. Abaixo está a lista de endpoints que estaremos criando.
HTTP POST /music | Adicionar nova música |
HTTP GET /music | Obter todas as músicas |
HTTP DELETE /music/:blogId | Excluir uma música |
Vamos começar criando a rota do blog. Vá até api/routes/music.js e escreva o seguinte 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 : Agora, sempre que fizermos uma solicitação get
para /music
. a rota chama a função getAllMusic
que está localizada no arquivo 'controllers'.
Vamos passar para api/controllers/musicController
para definir os controladores. Começamos escrevendo uma função para obter todas as músicas em nosso banco de dados usando o método mangusto db.collection.find
que retornará todos os itens dessa coleção.
Depois de fazer isso, escrevemos outra função que criará uma nova música no banco de dados. Precisamos criar uma nova instância de música usando a palavra-chave new
e depois definir o objeto de música. Depois de fazer isso, usaremos o método de save
do mangusto para adicionar novas músicas ao banco de dados.
Para excluir uma música, precisamos usar o método de remove
do mangusto simplesmente passando o ID da música como parâmetro na instância de remove
. Isso resulta em mangusto olhando para a coleção de música que tem esse ID específico e, em seguida, removendo-o dessa coleção.
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, mas não menos importante, para testar as rotas, precisamos registrar as rotas de música em nosso arquivo index.js :
const userRoutes = require("./api/user/route/user"); //bring in our user routes app.use("/user", userRoutes);
Testando os pontos finais
Para testar nossos endpoints, usaremos POSTMAN.
Adicionando novas músicas
Para testar a funcionalidade Add Music
, defina o método da solicitação clicando no menu suspenso de métodos. Depois de fazer isso, digite a URL do endpoint e clique na guia body para selecionar como deseja enviar seus dados. (No nosso caso, usaremos o método form-data.)
Então clique nos dados do formulário e configure sua chave de modelo. Ao configurá-lo, atribua algum valor às chaves, conforme mostrado na imagem abaixo:
Após fazer isso, clique em 'Enviar' para fazer a solicitação.
Listando todas as músicas
Para listar todas as músicas em nosso banco de dados, temos que digitar o URL do endpoint na seção URL fornecida. Após fazer isso, clique no botão 'Enviar' para fazer a solicitação.
Excluindo música
Para excluir uma música, precisamos passar o music id
como parâmetro.
É isso!
Construindo o Front-end
Para nosso frontend, usaremos um framework Vue: Nuxt.js.
“Nuxt é um framework progressivo baseado em Vue.js para criar aplicações web modernas. É baseado em bibliotecas oficiais Vue.js (vue, vue-router e vuex) e poderosas ferramentas de desenvolvimento (webpack, Babel e PostCSS).”
— Guia NuxtJS
Para criar um novo aplicativo Nuxt.js, abra seu terminal e digite o seguinte (com musicapp
como o nome do aplicativo que iremos construir):
$ npx create-nuxt-app musicapp
Durante o processo de instalação, serão feitas algumas perguntas sobre a configuração do projeto:
Project name | aplicativo de música |
project description | Um aplicativo gerenciador de música simples |
Author name | <seu nome> |
Package manager | npm |
UI framework | Bootstrap vue |
custom ui framework | Nenhum |
Nuxt modules | Axios,pwa (use a barra de espaço do teclado para selecionar itens) |
Linting tool | Mais bonito |
test framework | Nenhum |
Rendering Mode | Universal (SSR) |
development tool | Jsonconfig.json |
Depois de selecionar tudo isso, temos que esperar um pouco para que o projeto seja configurado. Quando estiver pronto, vá para a pasta /project
e veicule o projeto da seguinte forma:
cd musicapp && npm run dev
Abra o projeto em qualquer editor de código de sua escolha e depois abra o projeto no navegador acessando localhost:3000
.
Configurando o Axios
Usaremos axios
para fazer uma solicitação HTTP ao nosso servidor back-end. O Axios já está instalado em nosso projeto, então só precisamos configurar o baseURL
- para nosso servidor backend.
Para fazer isso, abra o arquivo nuxt.config.js no diretório root
e inclua a baseURL
no objeto axios
.
axios: { baseURL:'https://localhost:4000' },
Construindo o Gerenciador de Música
Configurando a IU
Vamos começar limpando a interface do usuário. Abra o arquivo pages/index.vue e remova todo o código com o seguinte:
<template> <div>Hello</div> </template>
Depois de fazer isso, você só poderá ver um “Olá” no navegador.
No diretório root
, crie uma pasta /partials
. Dentro da pasta /partials
partials, crie um arquivo navbar.vue e adicione o seguinte 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 o componente para navegar pelas páginas em nosso aplicativo. Este será apenas um componente simples feito de Bootstrap navbar
. Confira a documentação oficial do Bootstrap para mais referência.
Em seguida, vamos definir um layout personalizado para o aplicativo. Abra a pasta /layouts
, substitua o código no arquivo default.vue pelo código abaixo.
<template> <div> <navbar /> <nuxt /> </div> </template> <script> import navbar from '@/partial/navbar' export default { components: { navbar } } </script>
Importamos a barra de navbar
para este layout, o que significa que todas as páginas em nosso aplicativo terão esse componente de navbar
de navegação nela. (Este será o componente que todos os outros componentes em nosso aplicativo serão montados.)
Depois disso, você poderá ver isso no seu navegador:
Agora vamos configurar a interface do usuário para nosso gerente. Para fazer isso, precisamos criar uma pasta /manager
dentro da pasta de componentes e adicionar um arquivo na pasta chamada manager.vue .
Nesse arquivo, adicione o seguinte 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 : Este é apenas um modelo simples de Bootstrap para adicionar música em nosso aplicativo. O formulário definirá um modelo de tabela que listará todas as músicas que podem ser encontradas em nosso banco de dados.
Após definir este componente, precisamos registrá-lo na pasta /pages
para inicializar o roteamento.
O Nuxt.js não tem um arquivo 'router.js' como o Vue.js. Ele usa a pasta pages para roteamento. Para obter mais detalhes, visite o site Nuxt.js.
Para registrar o componente, crie uma pasta /manager
dentro da pasta /pages
e crie um arquivo index.vue . Em seguida, coloque o seguinte código dentro do arquivo:
<template> <div> <manager /> </div> </template> <script> import manager from '@/components/manager/manager' export default { components: { manager } } </script>
Este é o componente que irá renderizar em nossa rota de pages
.
Depois de fazer isso, vá para o seu navegador e navegue até /manager
- você deve estar vendo isso:
Listando todas as músicas
Vamos continuar criando uma função que irá buscar todas as músicas. Esta função será registrada no gancho de ciclo de vida criado, de forma que sempre que o componente for criado, a função será chamada.
Vamos começar criando uma variável na instância vue
que conterá todas as músicas:
allmusic = []; musicLoading: false,
Em seguida, defina uma função getAllMusics
e adicione o seguinte 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') } }
Em seguida, registre-se no gancho do ciclo de vida criado:
created() { this.getAllMusics() }
Emitindo os dados
Agora é hora de produzir todas as músicas na mesa que criamos 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>
Lembra daquela tabela que criamos anteriormente? Bem, precisaremos percorrer a resposta que recebemos de nosso back-end para listar todas as músicas recebidas de volta do banco de dados.
Adicionando música
Para adicionar uma nova música, precisamos fazer uma solicitação HTTP ao servidor back-end com os detalhes da música. Para fazer isso, vamos começar modificando o formulário e o tratamento dos uploads de arquivos.
No formulário, precisamos adicionar um ouvinte de event
que ouvirá o formulário quando ele for enviado. No campo de input
, adicionamos um v-
-model para vincular o valor ao 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>
E a seção de script deve ficar assim:
<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 uma função que enviará uma solicitação ao nosso serviço de back-end para criar qualquer nova música que tenha sido adicionada à lista. Também. precisamos escrever uma função de validação simples que verificará o tipo de arquivo para que os usuários só possam fazer upload de arquivos com uma extensão de .mp3 e .mp4 .
É importante definir uma propriedade computada para garantir que nosso campo de entrada não esteja vazio. Também precisamos adicionar um validador simples que garantirá que o arquivo que estamos tentando enviar seja realmente um arquivo de música.
Vamos continuar editando a função addMusic
para fazer uma solicitação ao nosso serviço de back-end. Mas antes de fazermos isso, vamos primeiro instalar o sweetalert
que nos fornecerá uma boa janela modal. Para fazer isso, abra seu terminal e digite o seguinte:
npm i sweetalert
Depois de instalar o pacote, crie um arquivo sweetalert.js na pasta /plugins
e adicione isto:
import Vue from 'vue'; import swal from 'sweetalert'; Vue.prototype.$swal = swal;
Em seguida, registre o plugin no arquivo nuxt.config.js dentro da instância do plugin assim:
plugins: [ { src: '~/plugins/sweetalert' } ],
Agora configuramos com sucesso sweetalert
em nosso aplicativo, para que possamos seguir em frente e editar a função addmusic
para isso:
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 } },
Vamos escrever um script simples que alterne o formulário, ou seja, ele só deve ser exibido quando quisermos adicionar novas músicas.
Podemos fazer isso editando o botão 'Adicionar música' na tabela que exibe todas as músicas que podem ser encontradas:
<button class="btn btn-info m-3" @click="initForm"> {{addState?"Cancel":"Add New Music"}} </button>
Em seguida, adicione um estado que manterá o estado do formulário na propriedade data
:
addState: false
Depois de fazer isso, vamos definir a função initForm
:
initForm() { this.addState = !this.addState },
E, em seguida, adicione v-if="addState"
ao div
que contém o formulário:
<div class="card" v-if="addState">
Excluindo música
Para excluir música, precisamos chamar o endpoint delete
e passar o music id
como um parâmetro. Vamos adicionar um evento de click
ao botão 'Excluir' que acionará a função para excluir uma função:
<button class="btn btn-info" @click="deleteMusic(music._id)">Delete</button>
A função delete
fará uma solicitação HTTP para nosso serviço de back-end. Depois de obter o ID da música do parâmetro da função deleteMusic
, adicionaremos o ID na URL que estamos usando para enviar a solicitação. Isso especifica a música exata que deve ser removida do banco de dados.
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!') } }) }
Com tudo isso, acabamos de construir nosso gerenciador de música. Agora é hora de construir o player de música.
Vamos começar criando uma nova pasta na pasta de componentes chamada /player
. Em seguida, crie um arquivo player.vue dentro desta pasta e adicione isto:
<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>
Em seguida, vamos importar este componente para o arquivo index.vue na pasta /pages
. Substitua o código no arquivo index.vue por este:
<template> <div> <player /> </div> </template> <script> import player from '@/components/player/player' export default { components: { player } } </script>
Vamos configurar o roteamento em nosso componente navbar
para habilitar o roteamento entre nossas páginas.
Para rotear em um aplicativo Nuxt.js, o nuxt-link
é usado após o qual você especificou a página dessa rota para uma instância específica. Então, vamos editar o código no componente partials/navbar
para isso:
<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>
Com isso, podemos navegar pelas nossas páginas usando a barra de navegação.
Construindo o jogador
Antes de começarmos, precisamos estender o Webpack para carregar arquivos de áudio. Os arquivos de áudio devem ser processados pelo file-loader
. Este carregador já está incluído na configuração padrão do Webpack, mas não está configurado para lidar com arquivos de áudio.
Para fazer isso, acesse o arquivo nuxt.config.js e modifique o objeto de build
para este:
build: { extend(config, ctx) { config.module.rules.push({ test: /\.(ogg|mp3|mp4|wav|mpe?g)$/i, loader: 'file-loader', options: { name: '\[path\][name].[ext]' } }) } }
Em seguida, vamos escrever uma função que obterá todas as músicas e, em seguida, usar o construtor Audio
para reproduzir a primeira música no array allMusic
.
Para começar, vamos modificar nosso arquivo player.vue para este:
<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>
Depois que o arquivo for servido, a música será reproduzida em segundo plano e você poderá ver isso no seu navegador:
Para parar a música, tudo que você precisa fazer é comentar o await await player.play()
na função initPlayer
.
Criando a IU do Player
Vamos agora definir nossa interface de usuário do music player substituindo o modelo em nosso arquivo player.vue pelo seguinte:
<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>
Em seguida, adicione o seguinte estilo na seção 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>
Depois de modificar isso, o player deve ficar assim:
Adicionando a função de reprodução
Continuaremos exibindo a descrição da música na mesa. Para isso, substitua a tabela pelo código abaixo:
<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>
Não queremos exibir os ícones 'Reproduzir' e 'Pausar' ao mesmo tempo. Em vez disso, queremos uma situação em que, quando a música estiver tocando, o ícone 'Pause' seja exibido. Além disso, quando a música é pausada, o ícone de reprodução deve ser exibido.
Para conseguir isso, precisamos definir um estado isPlaying
para a instância false
e, em seguida, usar essa instância para alternar os ícones. Depois disso, adicionaremos uma função ao nosso ícone 'Play'.
isplaying:false
Depois de fazer isso, modifique seu ícone 'Play' e 'Pause' para este:
<i class="fas fa-play play" v-if="!isplaying" @click="play"></i> <i class="fas fa-pause play" v-else></i>
Com tudo isso vamos definir o método 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 },
Nós, em primeiro lugar, pegamos a música atual e a passamos para o parâmetro da function
. Em seguida, definimos a instância JavaScript Audio()
. Em seguida, verificamos se a música é nula: se não for, configuramos this.current
para a música que passamos no parâmetro e, em seguida, chamamos a instância do player de Audio
. (Além disso, não esqueça que temos que definir o estado isPlaying
como true
quando a música estiver tocando.)
Adicionando a função de pausa
Para pausar uma música, usaremos o método de pausa de Audio
. Precisamos adicionar um evento de click
ao ícone de pausa:
<i class="fas fa-pause play" @click="pause" v-else></i>
E então defina a função na instância de methods
:
pause() { this.player.pause() this.isplaying = false },
Tocando uma música da lista de músicas
Isso é bem simples de implementar. Tudo o que precisamos fazer é adicionar um evento de click
que mudará o parâmetro da song
no método de play
da música que acabamos de criar.
Basta modificar o botão play
na tabela da lista de músicas para isto:
<button class="btn btn-primary" @click="play(music)">Play</button>
E aí está!
Adicionando a próxima função
Para adicionar a próxima função, precisamos incrementar o índice em um. Para fazer isso, adicione um evento de click
ao próximo ícone:
@click="next"
E então defina a função prev
na instância 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) },
Essa condicional é responsável por reproduzir todas as músicas sempre que a última música da lista for reproduzida.
Adicionando a função previous
Na verdade, isso é o oposto da próxima função, então vamos adicionar um evento de click
à função anterior:
@click="prev"
Em seguida, definimos a função anterior:
prev() { this.index-- if (this.index < 0) { this.index = this.allMusic.length - 1 } this.current = this.allMusic[this.index] this.play(this.current) },
Nosso aplicativo de player de música agora está completo!
Conclusão
Neste artigo, vimos como podemos criar um gerenciador de música com Nuxt.js e Express.js. Ao longo do caminho, vimos como o Multer agiliza o processo de manipulação de uploads de arquivos e como usar o Mongoose para interagir sem um banco de dados. Por fim, usamos o Nuxt.js para criar o aplicativo cliente, o que lhe dá uma sensação rápida e ágil.
Ao contrário de outros frameworks, construir um aplicativo com Nuxt.js e Express.js é bastante fácil e rápido. A parte legal do Nuxt.js é a maneira como ele gerencia suas rotas e faz com que você estruture melhor seus aplicativos.
- Você pode acessar mais informações sobre Nuxt.js aqui.
- Você pode acessar o código-fonte no Github aqui