# Eventos Customizados

Esta página assume que você já leu o Básico sobre Componentes. Leia lá antes se você está iniciando com componentes.

# Nomes de Eventos

Diferente de componentes e propriedades, os nomes de eventos não convertem automaticamente maiúsculas e minúsculas. Em vez disso, o nome de um evento emitido deve corresponder exatamente ao nome usado para escutar este evento. Por exemplo, se emitir um evento com nome em camelCase:

this.$emit('myEvent')
1

Escutar com kebab-case não funcionará:

<!-- Não funcionará -->
<my-component @my-event="doSomething"></my-component>
1
2

Considerando que os nomes de eventos nunca serão usados como nomes de variáveis ou de propriedades no JavaScript, não há razão para usar camelCase ou PascalCase. Além disso, escutadores de eventos v-on dentro dos templates DOM serão automaticamente transformados em minúsculas (devido ao HTML ser insensível à maiúsculas e minúsculas), então @myEvent se tornará @myevent -- fazendo myEvent impossível de ser escutado.

Por estas razões, nós recomendamos que você sempre use kebab-case para nomes de eventos.

# Definindo Eventos Customizados

Assista um vídeo grátis sobre como definir Eventos Customizados na Vue School (em inglês)

Os eventos emitidos podem ser definidos no componente através da opção emits.

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

Quando um evento nativo (por exemplo, click) for definido na opção emits, o evento do componente será usado ao invés de um escutador de evento nativo.

DICA

Recomenda-se definir todos os eventos emitidos para documentar melhor como o componente deve funcionar.

# Validar Eventos Emitidos

Semelhante à validação de propriedades, um evento emitido pode ser validado se for definido com a sintaxe Object em vez da sintaxe Array.

Para adicionar validação, o evento recebe uma função que recebe os argumentos passados ​​para a chamada $emit e retorna um booleano para indicar se o evento é válido ou não.

app.component('custom-form', {
  emits: {
    // Sem validação
    click: null,

    // Validar evento submit
    submit: ({ email, password }) => {
      if (email && password) {
        return true
      } else {
        console.warn('Argumentos inválidos para o evento submit!')
        return false
      }
    }
  },
  methods: {
    submitForm() {
      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 do v-model

Por padrão, em um componente o v-model usa modelValue como propriedade e update:modelValue como evento. Podemos modificar esses nomes passando um argumento para v-model:

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

Nesse caso, o componente filho espera a propriedade title e emite o evento update:title para sincronizar:

const app = Vue.createApp({})

app.component('my-component', {
  props: {
    title: String
  },
  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
13
<my-component v-model:title="bookTitle"></my-component>
1

# Múltiplos Vínculos v-model

Aproveitando a capacidade de direcionar uma determinada propriedade e evento como aprendemos antes em argumentos do v-model, agora podemos criar múltiplos vínculos de v-model em uma única instância do componente.

Cada v-model será sincronizado com uma propriedade diferente, sem a necessidade de opções extras no componente:

<user-name
  v-model:first-name="firstName"
  v-model:last-name="lastName"
></user-name>
1
2
3
4
const app = Vue.createApp({})

app.component('user-name', {
  props: {
    firstName: String,
    lastName: String
  },
  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
19

Veja o exemplo Múltiplos v-models por L. Tonet (@lucianotonet) no CodePen.

# Manipulando Modificadores do v-model

Quando estávamos aprendendo sobre interligações em elementos input, vimos que v-model tem modificadores embutidos - .trim, .number e .lazy. Em alguns casos, entretanto, você também pode querer adicionar seus próprios modificadores personalizados.

Vamos criar um modificador personalizado de exemplo, capitalize, que coloca em maiúscula a primeira letra da string fornecida pela vinculação v-model.

Modificadores adicionados ao v-model de um componente serão fornecidos ao componente por meio da propriedade modelModifiers. No exemplo abaixo, criamos um componente que contém uma propriedade modelModifiers cujo padrão é um objeto vazio.

Observe que quando o gatilho do ciclo de vida created do componente é acionado, a propriedade modelModifiers contém capitalize e seu valor é true - devido ao fato de ser definido na vinculação v-model.capitalize="bar".

<my-component v-model.capitalize="bar"></my-component>
1
app.component('my-component', {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  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

Agora que temos nossa propriedade configurada, podemos verificar as chaves do objeto modelModifiers e escrever um manipulador para alterar o valor emitido. No código a seguir, colocaremos a string em maiúscula sempre que o elemento <input /> disparar um 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: () => ({})
    }
  },
  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

Para os vínculos v-model com argumentos, o nome da propriedade gerada será arg + "Modifiers":

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

Deployed on Netlify.
Atualizado pela última vez: 10/16/2020, 2:48:36 PM