# Eventos Personalizados

Esta página asume que usted ya ha leído Básicos de Componentes. Léalo primero si usted es nuevo con componentes.

# Nombre de eventos

Como los componentes y props, los nombres de eventos proporcionan una transformación automática de casos. Si emite un evento desde el componente secundario con un nombre de camelCase, será capaz de agregar un escuchador de kebab-case en el componente padre.

this.$emit('myEvent')
1
<my-component @my-event="doSomething"></my-component>
1

Como con Casos de Props, recomendamos utilizar escuchadores de eventos de kebab-case cuando está utilizando plantillas en DOM. Si está utilizando plantillas de cadena de caracteres, esta limitación no se aplica.

# Definir eventos personalizados

Ver un video gratis sobre cómo definir eventos personalizados en Vue School

Los eventos emitidos pueden ser definido en el componente mediante la opción emits.

app.component('custom-form', {
  emits: ['inFocus', 'submit']
})
1
2
3

Cuando un evento nativo (p. ej. click) está definido en la opción emits, el evento de componente será utilizado en vez de un escuchador de evento nativo.

TIP

Es recomendado definir todos eventos emitidos para documentar mejor cómo un componente debería funcionar.

# Validar eventos emitidos

Similar a las validaciones de props, un evento emitido puede ser validado si es definido con la sintaxis de objeto en vez de matriz.

Para agregar validación, una función está asignado al evento, la que recibe los argumentos pasados a la llamada de $emit y retorna un valor booleano para indicar si el evento es válido o no.

app.component('custom-form', {
  emits: {
    // no validación
    click: null,

    // Validar el evento _submit_
    submit: ({ email, password }) => {
      if (email && password) {
        return true
      } else {
        console.warn('¡La carga del evento submit es inválida!')
        return false
      }
    }
  },
  methods: {
    submitForm(email, password) {
      this.$emit('submit', { email, password })
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# Argumentos de v-model

Por defecto, v-model de un componente utiliza modelValue como la prop y update:modelValue como el evento. Podemos modificar estes nombres pasando un argumento a v-model:

<my-component v-model:title="bookTitle"></my-component>
1

En este caso, el componente secundario esperará una prop title y emitirá evento update:title para sincronizar.

app.component('my-component', {
  props: {
    title: String
  },
  emits: ['update:title'],
  template: `
    <input
      type="text"
      :value="title"
      @input="$emit('update:title', $event.target.value)">
  `
})
1
2
3
4
5
6
7
8
9
10
11
12

# Múltiples vinculaciones de v-model

Al aprovechar la capacidad para dirigir una prop u evento particular como aprendemos antes con argumentos de v-model, podemos ahora crear múltiples vinculaciones de v-model en una sola instancia de componente.

Cada v-model será sincronizado con una prop diferente, sin la necesidad de opciones adicionales en el componente:

<user-name
  v-model:first-name="firstName"
  v-model:last-name="lastName"
></user-name>
1
2
3
4
app.component('user-name', {
  props: {
    firstName: String,
    lastName: String
  },
  emits: ['update:firstName', 'update:lastName'],
  template: `
    <input
      type="text"
      :value="firstName"
      @input="$emit('update:firstName', $event.target.value)">

    <input
      type="text"
      :value="lastName"
      @input="$emit('update:lastName', $event.target.value)">
  `
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

See the Pen Múltiples directivas de v-model by Vue (@Vue) on CodePen.

# Manejar modificadores de v-model

Cuando estabamos aprendiendo sobre las vinculaciones de entradas de formularios, vimos que v-model tiene modificadores integrados - .trim, .number y .lazy. En algunos casos, sin embargo, querría también agregar sus propios modificadores personalizados.

Creemos un ejemplo de modificador personalizado, capitalize, lo que pone en mayúscula la primera letra de la cadena de caracteres proporcionada por la vinculación de v-model.

Los modificadores agregados a v-model de un componente serán proporcionados al componente mediante la prop modelModifiers. En el siguiente ejemplo, hemos creado un componente que contiene una prop modelModifiers que utiliza un objeto vacío como su valor por defecto.

Note que cuando se activa el hook de ciclo de vida created del componente, la prop modelModifiers contiene capitalize y su valor es true - debido a que está establecido en la vinculación de v-model, es decir, v-model.capitalize="myText".

<my-component v-model.capitalize="myText"></my-component>
1
app.component('my-component', {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  template: `
    <input type="text"
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)">
  `,
  created() {
    console.log(this.modelModifiers) // { capitalize: true }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Ahora que tenemos nuestra prop establecida, podemos probar las claves del objeto modelModifiers y escribir un manejador para cambiar el valor emitido. En el código abajo vamos a poner en mayúscula la primera letra de la cadena de caracteres cada vez que el elemento <input /> dispare un evento input.

<div id="app">
  <my-component v-model.capitalize="myText"></my-component>
  {{ myText }}
</div>
1
2
3
4
const app = Vue.createApp({
  data() {
    return {
      myText: ''
    }
  }
})

app.component('my-component', {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  methods: {
    emitValue(e) {
      let value = e.target.value
      if (this.modelModifiers.capitalize) {
        value = value.charAt(0).toUpperCase() + value.slice(1)
      }
      this.$emit('update:modelValue', value)
    }
  },
  template: `<input
    type="text"
    :value="modelValue"
    @input="emitValue">`
})

app.mount('#app')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

Para las vinculaciones de v-model con argumentos, el nombre generado de la prop será arg + "Modifiers":

<my-component v-model:description.capitalize="myText"></my-component>
1
app.component('my-component', {
  props: ['description', 'descriptionModifiers'],
  emits: ['update:description'],
  template: `
    <input type="text"
      :value="description"
      @input="$emit('update:description', $event.target.value)">
  `,
  created() {
    console.log(this.descriptionModifiers) // { capitalize: true }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12