El conocimiento es el nuevo dinero.
Aprender es la nueva manera en la que inviertes
Acceso Cursos

Optimiza la carga de imágenes en Vue3 con este truco de emit

· 6 min de lectura
Optimiza la carga de imágenes en Vue3 con este truco de emit

Cuando trabajamos con Vue, tenemos muchas ventajas para que los componentes puedan comunicarse entre sí , entre ellos podemos hacer uso de Vuex o de Pinia. Sin embargo, EMIT, es un método súper útil que es imprescindibles si queremos crecer como profesionales y no caer en la repetición de código 😵‍💫, puesto que gracias este podemos crear componentes de forma eficiente y completa junto a su partner in crime🔫: los PROPS.

Por ahora continuemos con nuestro emit, esta funcionalidad dentro de Vue como los leerás en todos lados, es la forma en como nos comunicamos de un componente hijo a un componente padre. Lo sé, Lo sé, si todo el mundo ya te lo dice, cómo yo te ayudo si te voy a repetir lo mismo. Calm down and Vamo a calmarno, tu confía en mí 😏 que esto saldrá precioso.

Al principio yo también estaba confundido, porque a diferencia de los props, el emit no son intuitivos, y es que este concepto abstracto debes de imaginarlo como el gatillo de una pistola ,(de agua, no queremos heridos), y es que lo ubicas y lo disparas donde se requiera, y no necesariamente como una prop en su respectiva sección.

Por lo que vamos a crear un componente que obtenga una imagen, y esta data obtenida de la imagen la vamos a pasar a su componente padre, una vez allí la renderizamos en pantalla.

No esta demás decirte que así como podemos enviar este File, podemos enviar lo que queramos, strings, numbers, y objetos enteros. Ahora sí, menos bla bla, y más coding time.

Para este mini proyecto vamos a hacer uso de Vite  escogeremos la opción de Vue, para este utorial tambíen usaremos Vue3, que en lo personal es increíble, por ahora ubiquémonos donde vas a crear el proyecto y hagamos lo siguiente

vuejs npm create vite@latest
need to install the following packages:
Create-vite@latest
Ok to proceed? (y) y
? Project name: > emit-file

Tomamos la opción de vue y javascript como lenguaje de programación

✔︎Select a framework > - vue
? Select a variant > - Use arrow-keys. Return to submit
> Javascript
Typescript
Customize with create-vue
Nuxt

Ahora ingresamos a nuestro proyecto y corramos nuestro proyecto

-> vuejs cd emit-file && npm install
-> emit-file npm run dev && code .

Con esto listo, ingresamos a nuestro navegador al puerto que nos indica la consola, este caso el puerto localhost:5173, y tenemos lo siguiente

Ahora aprovecharemos el componente de la vista App.vue para que sea nuestro componente padre, y de allí, crearemos dentro de la carpeta components el archivo UploadImage.vue para que capture el objecto de la imagen y que el padre lo renderice. Este es el código de nuestro componente hijo UploadImage.vue

<script setup>
const emit = defineEmits(['pass-image']);

function onFileChange(event) {
  const file = event.target.files[0];
  emit('pass-image', file)
}

</script>

<template>
  <div class="input-wrapper">
    <input
      type="file"
      class="input"
      accept="image/*"
      @change="onFileChange">
    <div class="fake-input">
      Subir archivo
    </div>
  </div>
</template>

<style scoped>
.input-wrapper {
  width: 120px;
  padding: 4px 8px;
  position: relative;
  margin: auto;
}
.input {
  opacity: 0;
  cursor: pointer;
}
.fake-input {
  width: 100%;
  height: 100%;
  border-radius: 4px;
  background-color: #41b883;
  color: white;
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  pointer-events: none;
}
</style>

Atención: observemos el script, estamos haciendo uso del macro defineEmits(), el cuál acepta un array, en el que declaramos los emits que deseemos, en este caso colocaremos solo uno pass-image, esto nos devuelve una función lista que hará uso de la variable que escogimos, en este caso, para ser descriptivos hice uso de la palabra emit como variable, lo que nos permitirá usar de esta función donde deseemos

Ahora con la función emit lista para utilizarse, este es ejecutado dentro de la función onFileChange(), donde primero se coloca el nombre del emit que usaremos y como segundo parámetro la data que queramos, tales como: un objeto; un string, un número, en esta situación, pasaremos nuestro File, hacia el componente padre

OJO👁️: el emit se dispará (como gatillo de pistola), solo cuando la función donde se encuentre sea ejecutada, será ese el momento donde el padre sabrá que algo ha sido emitido desde su componente hijo

Ahora con nuestro componente listo para usarse (UploadImage.vue), que acepta solo imágenes en este caso, lo importaremos dentro del archivo App.vue, el cuál servirá como componente padre y es el qué escuchará el evento emitido, el código queda de la siguiente manera

<script setup>
import { ref } from 'vue';
import UploadImage from './components/UploadImage.vue';

const image = ref('')

function getImage(file) {
  const url = URL.createObjectURL(file)
  image.value = url
}
</script>

<template>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <UploadImage @pass-image="getImage" />
  <img
    v-if="image.length"
    :src="image"
    class="image"
    alt="example">
</template>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
.image {
  margin-top: 24px;
  width: 300px;
  height: 240px;
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
}
</style>

Lo único que hacemos aquí es declarar nuestro componente, pero con un detalle, hacemos uso del @ para dar a conocer el componente padre, que ese componente tiene un emit que debe escuchar en caso de que sea disparado, y cuando esto suceda, inmediatamente se ejecuta la función que reciba el evento emitido, que para nuestro script es la función getImage(), una vez ejecutada la función, esta recibe un parámetro de forma implícita en donde viene guardada la imagen, como observamos, en este caso lo recibimos con la palabra file, una vez tomando el objeto que hemos recibido de nuestro emit, lo convertiremos de un file a un url, y este url será guardada en la variable image, con esto podemos cargar la imagen en el componente padre con la etiqueta src que hemos colocado  

Con los scripts que hemos creado, es suficiente para que veamos lo siguiente en pantalla antes de cargar nuestra imagen

Y al hacer click en nuestro botón de subir imagen podremos capturar la imagen emitida desde el UploadImage.vue (HIJO) y este será escuchado en el componente padre App.vue (PADRE), para luego renderizar en pantalla, obteniendo lo siguiente:

Amazing 😲, la imagen se ha cargado exitosamente emitidiendo el archivo y el padre tomándolo y renderizándolo en pantalla. Ahora tratemos de realizar un pequeño flujo de lo que ocurre aquí

UploadImage.vueClick en el input             |Se ejecuta onFileChange()             |Dentro de onFileChange se dispará el emit(´pass-image´)
App.vuex

Junto al disparo del emit (pass-image), se ejecuta la función `getImage()`
                                                        |
Se convierte la imagen a un url para que sea guardada en la constante image
                                                        |
Se renderiza en pantalla la imagen en nuestro componente padre

UUUUUUUUFFFFF 🥳 yyyyyy estamos listos para crear componentes padres que reciban una imágen sin ningún problema, fácil y escalable y como todos unos profesionales que somos a lo largo y ancho de nuestra aplicación 😎

Un placer acompañarte en esta aventura y como siempre puedes seguirme en mis redes y por supuesto tienes el proyecto de ejemplo aquí 🥸

Plataforma de cursos gratis sobre programación