Simple Modal
Simple modal built on Vue and Typescript.
Properties
-
title
: Title of the modal -
open
: Flag that indicates if the modal is or not opened.
Events
-
close
: Fired on close click.
Posted on January 22, 2019
Uno de los frameworks JavaScript que más ha crecido este último año ha sido Vue. Este framework, caracterizado por su sencillez y a la vez, su potencia, ha tomado por asalto la comunidad frontend.
No por nada Vue ha superado a React y Angular en popularidad en Github aunque no quiere decir que a nivel de uso por parte de los desarrolladores se mantenga la misma equivalencia. Lo cierto es que Vue es un framework increíble, flexible, potente y lleno de posibilidades. Aprovecho para felicitar a Evan You y a todo el equipo y contribuyentes detrás de Vue. Congratz guys, you're awesome!
Bien, empecemos. Lo primero que vamos a necesitar es inicializar el proyecto e instalar algunas dependencias. Vamos a dividir las dependencias en dos: dependencias de desarrollo y de funcionamiento.
Las dependencias de desarollo serán básicamente loaders para Typescript y Vue. Estas son:
Y las depenencias principales son:
Ahora que tenemos las dependencias instaladas, procedemos a crear un archivo llamado tsconfig.json
, el cual leerá Typescript para tomar en cuenta algunas configuraciones.
{
"include": [
"./src/**/*"
],
"compilerOptions": {
"target": "esnext",
"lib": ["dom", "esnext"],
"module": "es2015",
"moduleResolution": "node",
"noUnusedLocals": true,
"noUnusedParameters": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
"compileOnSave": false
}
Lo que hacemos es, en teoría, decirle que tenga en cuenta a cualquier archivo dentro de src/
, que queremos usar ES Modules y que active el uso de decoradores.
Una vez realizado este paso, lo siguiente es preparar el archivo de configuración de Webpack:
const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
context: __dirname,
entry: './src/index.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
resolve: {
alias: {
vue$: 'vue/dist/vue.esm.js'
},
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/]
}
}
},
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
},
{
test: /\.vue$/,
exclude: /node_modules/,
use: {
loader: 'vue-loader'
}
}
]
},
devtool: 'sourcemap',
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
}
Utilizaremos html-webpack-plugin para levantar webpack-dev-server. El archivo index.html
lo ponemos en la carpeta src
de nuestro proyecto. Quedará así:
<!DOCTYPE html>
<html lang="en">
<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">
<title>Simple Modal</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
Ahora, seguimos con el entry point de nuestra aplicación. Aquí levantaremos Vue junto con el componente principal.
import Vue from 'vue'
import App from './index.vue'
new Vue({
el: '#app',
template: '<App/>',
render: h => h(App)
})
Ya tenemos todo listo para empezar con la creación de la modal.
La modal será sencilla y orientada a componentes. Realizaremos la estructura, mapearemos algunas propiedades y estableceremos los eventos que debe emitir. El contenido de la modal será insertado de acuerdo a lo que necesitemos en cada ocasión.
Lo primero será crear el template:
Nota: recuerda que tanto el template, como style y script va dentro de un archivo
.vue
.
<template>
<div class="modal" :class="{ open }">
<div class="modal-content">
<header class="modal-header">
<h3>{{ title }}</h3>
<span @click="close">×</span>
</header>
<article class="modal-body">
<slot name="content"></slot>
</article>
<footer class="modal-footer">
<slot name="actions"></slot>
</footer>
</div>
</div>
</template>
Como se puede ver a simple vista, es una estructura bastante sencilla. El título de la modal deberá ser proporcionado por
medio de una la propiedad title
, además, el sabremos si está abierta o cerrada por medio de la propiedad open
.
La siguiente línea:
<span @click="close">×</span>
Nos dice que cuando se haga click en la "x", se ejecutará el método close
de nuestro componente.
Además, para poder mostrar u ocultar la modal, nos basaremos en esta línea:
<div class="modal" :class="{ open }">
Que nos indica que si la propiedad open
es true
, entonces se agregará una clase CSS llamada open
, la cual mostrará la modal con un efecto transitorio, como se puede apreciar en el código CSS:
<style scoped>
.modal {
align-items: flex-start;
background-color: rgba(0,0,0,.75);
display: flex;
height: 100vh;
justify-content: center;
opacity: 0;
position: fixed;
transition: visibility 250ms, opacity 250ms;
width: 100%;
z-index: -1;
}
.modal.open {
opacity: 1;
visibility: visible;
z-index: 2;
}
.modal.open .modal-content {
transform: translateY(100px);
}
.modal-content {
background-color: #fff;
border-radius: 2px;
box-shadow: 0 8px 16px 0 rgba(0,0,0,.25);
display: inline-block;
min-width: 320px;
max-width: 480px;
transition: transform 450ms ease;
width: 100%;
}
.modal-header {
border-bottom: 1px solid #eee;
padding: 20px;
position: relative;
text-align: center;
}
.modal-header h3 {
color: #444;
font-family: Arial, Helvetica, sans-serif;
font-size: 14px;
font-weight: 600;
text-transform: uppercase;
}
.modal-header span {
cursor: pointer;
font-weight: bolder;
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
}
.modal-body {
padding: 40px;
}
.modal-footer {
background-color: #f8f8f8;
border-top: 1px solid #eee;
display: flex;
justify-content: flex-end;
padding: 20px;
}
</style>
Nota: hacemos uso del atributo
scoped
para determinar que estos estilos serán encapsulados dentro del componente, evitando conflictos con el resto de estilos de la aplicación.
El código CSS anterior simplemente agrega una transición de opacidad a la modal, así mismo, hace que esta se deslice desde arriba hacia abajo, dando un efecto llamativo y suave.
Finalmente, escribimos nuestro componente principal, el que se comunica con el template y tiene las propiedades y métodos que el template necesitará consumir.
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
import { Prop, Emit } from 'vue-property-decorator'
@Component
export default class Modal extends Vue {
@Prop({ required: true, type: String }) title: string
@Prop({ required: true, type: Boolean, default: false }) open
@Emit('close')
close(): void {}
}
</script>
Lo primero que hacemos es importar los decoradores Component
, el cual sirve para indicarle a Vue que dicha clase es un componente, Prop
que indica que dicha variable es una prop que recibirá el componente y Emit
que indica que ese método emitirá un evento hacia el padre.
La propiedad title
y open
, como dijimos, son requeridas. Así mismo, open
será inicializada en false.
El método close
, al ser ejecutado emitirá un evento hacia el padre que contenga la modal, notificando que se quiere cerrar la modal.
Para utilizar la modal es bastante sencillo. Basta con incluirla en la lista de componentes y colocarla en el template. Veamos un ejempo.
<template>
<div class="container" @keypress="catchKey" tabindex="0">
<Modal :title="modalTitle" :open="modalOpened" @close="closeModal">
<template slot="content">
<blockquote>
<p>Debido a nuevas políticas de seguridad, a partir de hoy, 22 de Enero del 2019, usted es reponsable de la seguridad de sus archivos. Para saber como reforzar y manejar la seguridad de su cuenta, lea la <a href="#">Documentación.</a></p>
<caption>TI & Information Security</caption>
</blockquote>
</template>
<template slot="actions">
<button class="decline">Declinar</button>
<button class="accept">Aceptar</button>
</template>
</Modal>
<h1>Presiona O para abrir la modal</h1>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
import Modal from './modal.vue'
@Component({
components: {
Modal
}
})
export default class App extends Vue {
modalTitle = 'Alerta de seguridad'
modalOpened = false
MODAL_TRIGGER = 111
catchKey(e: KeyboardEvent) {
if (e.keyCode === this.MODAL_TRIGGER) {
this.modalOpened = true
}
}
closeModal() {
this.modalOpened = false
}
}
</script>
Como vemos, la propiedad title
de la modal está ligada con modalTitle
y open
con modalOpened
, de modo que, cuando se presione la tecla O se cambie el estado de modalOpened
a true
, mostrando la modal.
Fíjate en el método closeModal
, es este método el que se ejecutará en cuando se detecte que Modal
ha emitido un evento de tipo close
, sobre el cual estamos escuchando mediante la línea @close="closeModal"
.
Resultado
Como vemos, crear un componente en Vue es realmente sencillo. No nos tomará más de un par de horas de tener un componente relativamente complejo y funcional. Personalmente, creo que todo desarrollador Frontend debería de darle la oportunidad a este genial framework. 😉
Posted on January 22, 2019
Sign up to receive the latest update from our blog.