# Пользовательские события

Подразумевается, что уже изучили и разобрались с разделом Основы компонентов. Если нет — прочитайте его сначала.

# Стиль именования событий

Также как для компонентов и входных параметров, для имён событий выполняется автоматическое преобразование регистра. Если событие генерируется в дочернем компоненте в camelCase, то в родительском потребуется прослушивать в kebab-case:

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

Как и в случае с регистром входных параметров, рекомендуется использовать kebab-case при использовании DOM-шаблонов. Для строковых шаблонов этого ограничения не будет.

# Определение пользовательских событий

Посмотрите бесплатное видео об определении пользовательских событий на Vue School

События генерируемые компонентом можно объявить с помощью опции emits.

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

Если в опции emits объявить нативное событие (например, click), то будет использоваться событие компонента вместо отслеживания нативного события.

Совет

Рекомендуется объявлять все генерируемые события, чтобы лучше задокументировать как должен работать компонент.

# Валидация сгенерированных событий

Аналогично валидации входных параметров, также можно валидировать и генерируемые события, если они объявлены с помощью объектного синтаксиса или синтаксиса массива.

Для добавления валидации события нужно указать функцию, которая получит те аргументы, с которыми был вызван $emit, и возвращает булево, чтобы сообщить является ли событие корректным или нет.

app.component('custom-form', {
  emits: {
    // Без валидации
    click: null,

    // Валидация события submit
    submit: ({ email, password }) => {
      if (email && password) {
        return true
      } else {
        console.warn('Некорректные данные для генерации события submit!')
        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

# Аргументы v-model

При использовании v-model на компоненте по умолчанию используется входной параметр modelValue и событие update:modelValue. Их можно изменить через аргумент v-model:

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

Для такой записи дочерний компонент будет ожидать входной параметр title и должен будет генерировать событие update:title для синхронизации значения:

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

# Использование нескольких v-model

Развивая потенциал возможности настройки используемого входного параметра и события, как изучили выше с помощью аргумента v-model, теперь стало возможным одновременно использовать несколько привязок v-model на одном экземпляре компонента.

Каждая v-model будет синхронизироваться со своим входным параметром, не требуя дополнительных настроек в компоненте:

<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 Использование нескольких v-model by Vue (@Vue) on CodePen.

# Обработка модификаторов v-model

Изучая работу с формами, можно заметить, что у v-model есть встроенные модификаторы.trim, .number и .lazy. Но в некоторых случаях может потребоваться добавить пользовательские модификаторы.

Создадим для примера пользовательский модификатор capitalize, который станет делать заглавной первую букву строки, привязанной с помощью v-model.

Модификаторы, которые будут использоваться в v-model компонента нужно указывать через входной параметр modelModifiers. В примере ниже, у компонента есть входной параметр modelModifiers, который по умолчанию будет пустым объектом.

Обратите внимание, в хуке жизненного цикла created входной параметр modelModifiers будет содержать capitalize со значением true — потому что он используется на привязке v-model компонента 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
18

После настройки входного параметра теперь можно проверять ключи modelModifiers и реализовать обработчик для модификации значения. В примере ниже обработчик будет запускаться каждый раз, когда элемент <input /> генерирует событие 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

Если используется привязка v-model с аргументом, то имя входного параметра будет генерироваться таким образом arg + "модификатор":

<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
13