Crear chat con VueJS

En esta entrada aprenderemos a crear nuestro propio chat con el framework Vuejs, con express, que lo utilizarémos para levantar nuestro servidor, y socket.io, una librería que nos permite trabajar con eventos en tiempo real.

Estructura del proyecto

Vamos a comenzar nuestro proyecto dirigiéndonos a la carpeta donde queramos trabajar y creando el packaje.json mediante este comando:

npm init

Si aún no conoces qué es el archivo packaje.json, podemos entenderlo como un manifiesto donde aparecerá cierta información de nuestra aplicación. Una vez ejecutes este comando, se te hará una serie de pregunta para rellenar dicho archivo, te dejo como lo hemos completado nosotros:

{
  "name": "chat",
  "version": "1.0.0",
  "description": "chat vuejs",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Nigmacode",
  "license": "MIT"
}

Una vez ya tenemos nuestro packaje.json creado, vamos a crear un archivo index.html, un index.js y una carpeta public con un archivo style.css

index.html
index.js
package.json
public
   style.css

De esta forma, ya tendríamos nuestro proyecto estructurado y listo para comenzar.

Creando nuestro chat con VueJS

Instalando express y socket.io

Para comenzar, debemos instalar en nuestro proyecto express.js y socket.io, con el siguiente comando:

npm install --save express@4.16.3 socket.io

Index.js

Nos dirigimos al archivo index.js, dónde vamos a levantar nuestro servidor con express y definiremos el funcionamiento del socket:

//Inicializamos las constantes para trabajar con express y socket.io
const express = require('express');
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http);

//Declaramos la carpeta public y definimos la ruta raiz '/' a index.html 
app.use('/public', express.static(__dirname + '/public'));
app.get('/', (req, res) => res.sendfile(__dirname + '/index.html'));

//Conexión con socket
io.on('connection', (socket)=>{
    //Esta función recibirá un mensaje y lo enviará a todos los usuarios de chat
    socket.on('message', (msg) => io.emit('message', msg));
});

//Levantamos nuestro servidor en el puerto 3000
http.listen(3000, () => console.log('Escuchando en puerto 3000'));

Index.html

En el archivo index.html, en su cabecera, vamos a añardir el estilo de style.css, creado en la carpeta public y también añadiremos el CDN de bootstrap:

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <!--Añadimos los estilos de la carpeta public y el cdn de bootstrap-->
    <link rel="stylesheet" href="/public/style.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <title>Chat con Vuejs</title>
</head>

En el body, crearemos un container con id app, que será el contenedor dónde trabajaremos con Vuejs y, al final, añadiremos su CDN y socket.io:

<body>
    <!-- Creamos el contenedor con ID APP dénde trabajaremos con VueJS-->
    <div id="app">
        <div class="container-fluid">
            <div class="row">
                <div class="col-md-6 offset-md-3">
                    <h1 class="title-page">Chat en Vuejs</h1>
                    <div class="container-chat">
                        <ul id="chat">
                            <!--Recorremos el array de mensajes y mostramos uno por uno en la lista-->
                            <li v-for="m in messages">
                                {{m}}
                            </li>
                        </ul>
                        <!-- con el atributo submit, le indicamos que al usar el input submit llamaremos a la funcíon sendMessage-->
                        <form @submit.prevent="sendMessage">
                            <input type="text" placeHolder="Mensaje..." v-model="message" class="form-control">
                            <input type="submit" value="Enviar" class="btn btn-chat">
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="/socket.io/socket.io.js"></script>
</body>

Por último, antes de cerrrar el body, vamos a crear una instancia de Vuejs, dónde declararemos:

-Variable message: Recogerá el valor que envía el usuario.

-Array messages: Array con los mensajes de los usuarios.

-Método sendMessage: Que enviará mediante emit el evento message, que se recibirá como vimos en el archivo index.js y se enviará a todos los usuarios añadiendose en el array messages.

-Created: se inicializa la variable socket.

-Mounted: se añade los mensajes que se han recibido al array.

<script>
        //inicializamos la variable socket que utilizaremos en created
        var socket = null;
        var app = new Vue({
            el:'#app',
            data:{
                //Inicializamos las variables
                message:'',
                messages: []
            },
            methods:{
                /*Creamos la funcion sendMessage, que será la que envíe mediante socket 
                 el mensaje y lo recibiran todos los usuarios en su navegador, 
                 añadiendose éste al  array messages de cada usuario*/ 
                sendMessage:function(){
                    socket.emit('message', this.message);
                    this.message = '';
                }
            },
            //Inicialización de la variable socket
            created: function(){
                socket = io();
            },
            //Se reciben los mensajes y se añaden al array
            mounted: function(){
                socket.on('message', function(message){
                    app.messages.push(message);
                });
            }
        });
    </script>

Style.css

Por último, le añadiremos un estilo a nuestro chat en el archivo style.css sumado al de bootstrap:

body{
    background-image: linear-gradient(to right, #4680A0, #5A2A8E);
    width:100%;
}
#chat{
    height: 500px;
    width: 100%;
    overflow-y:scroll;
    list-style: none;
    padding:0;
}
#chat li{
    padding:0.3rem 0rem 0.3rem 0.5rem;
    border-bottom: 1px solid #dedede;
}
.title-page{
    text-align: center;
    color:white;
    padding-top:0.6rem;
    padding-bottom:0.6rem;
}
.container-chat{
    background-color:white;
    border-radius: 5px;

}
.btn.btn-chat{
    color:white;
    background-color:#41B883;
    width: 100%;
    border-radius: 0px;
    font-size: 1.5rem;
}

y correríamos nuestro servidor, mendiante el comando:

<!-- corre nuestro servidor en localhost:3000 -->
node index.js

El resultado sería el siguiente: