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

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

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

Аналогично компонентам и входным параметрам, имена событий также предоставляют автоматическое преобразование регистра. Если событие генерируется в дочернем компоненте в 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() {
      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
<my-component v-model:title="bookTitle"></my-component>
1

# Использование нескольких 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 Multiple v-models 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 + "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
13

Deployed on Netlify.
Последнее обновление: 2021-01-10, 11:06:01 UTC